diff --git "a/\343\200\22002\343\200\221SQL \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store" "b/\343\200\22002\343\200\221SQL \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store"
new file mode 100644
index 0000000..7281db4
Binary files /dev/null and "b/\343\200\22002\343\200\221SQL \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store" differ
diff --git "a/\343\200\22002\343\200\221SQL \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/img/.DS_Store" "b/\343\200\22002\343\200\221SQL \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/img/.DS_Store"
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and "b/\343\200\22002\343\200\221SQL \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/img/.DS_Store" differ
diff --git "a/\343\200\22003\343\200\221XSS \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store" "b/\343\200\22003\343\200\221XSS \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store"
new file mode 100644
index 0000000..4da8b32
Binary files /dev/null and "b/\343\200\22003\343\200\221XSS \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store" differ
diff --git "a/\343\200\22003\343\200\221XSS \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/img/.DS_Store" "b/\343\200\22003\343\200\221XSS \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/img/.DS_Store"
new file mode 100644
index 0000000..89fd26c
Binary files /dev/null and "b/\343\200\22003\343\200\221XSS \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/img/.DS_Store" differ
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store"
new file mode 100644
index 0000000..20e0909
Binary files /dev/null and "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/.DS_Store" differ
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-default-2.5.0.war" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-default-2.5.0.war"
new file mode 100644
index 0000000..2ac75c6
Binary files /dev/null and "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-default-2.5.0.war" differ
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-default-2.9.1.war" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-default-2.9.1.war"
new file mode 100644
index 0000000..192789e
Binary files /dev/null and "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-default-2.9.1.war" differ
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.circleci/circle-v1.yml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.circleci/circle-v1.yml"
new file mode 100755
index 0000000..0fb0f1c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.circleci/circle-v1.yml"
@@ -0,0 +1,40 @@
+machine:
+ node:
+ version: 6.9.1
+ java:
+ version: oraclejdk8
+ environment:
+ PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin"
+
+branches:
+ only:
+ - master
+
+dependencies:
+ pre:
+ - rm -rf ~/.yarn
+ - npm install --global yarn
+ override:
+ - mvn --batch-mode install
+ cache_directories:
+ - ~/.cache/yarn
+
+test:
+ override:
+ - echo true
+
+general:
+ artifacts:
+ - '**/target/*.jar'
+ - '**/target/*.war'
+ - '**/target/classes/features.xml'
+
+deployment:
+ website:
+ branch: master
+ owner: hawtio
+ commands:
+ - git config --global user.email "circleci@mail.com"
+ - git config --global user.name "CircleCI"
+ - ./ci-website.sh
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.circleci/config.yml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.circleci/config.yml"
new file mode 100755
index 0000000..546b6fd
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.circleci/config.yml"
@@ -0,0 +1,22 @@
+# Javascript Node CircleCI 2.0 configuration file
+#
+# Check https://circleci.com/docs/2.0/language-java/ for more details
+#
+version: 2
+jobs:
+ build:
+ working_directory: ~/hawtio
+ docker:
+ - image: circleci/openjdk:8-browsers
+ steps:
+ - checkout
+ - restore_cache:
+ key: dependency-cache-{{ checksum "pom.xml" }}
+ - run:
+ command: mvn --batch-mode install
+ environment:
+ MAVEN_OPTS: -showversion -Xms256m -Xmx4096m
+ - save_cache:
+ paths:
+ - ~/.m2
+ key: dependency-cache-{{ checksum "pom.xml" }}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.editorconfig" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.editorconfig"
new file mode 100755
index 0000000..f0881c0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.editorconfig"
@@ -0,0 +1,11 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+
+[*.java]
+indent_size = 4
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.gitignore" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.gitignore"
new file mode 100755
index 0000000..aa6d138
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/.gitignore"
@@ -0,0 +1,24 @@
+target
+*.iml
+*.ipr
+*.iws
+*.log
+*.out
+overlays
+.DS_Store
+.settings
+.project
+.classpath
+runtime-EclipseApplication-m2eclipse
+.metadata
+/runtime-*/
+./fabric
+./fuseenterprise
+.idea
+tags
+node_modules
+hawtio-config
+.tscache
+node/
+bower_components/
+.vscode
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/BUILDING.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/BUILDING.md"
new file mode 100755
index 0000000..522cef8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/BUILDING.md"
@@ -0,0 +1,272 @@
+We love [contributions](http://hawt.io/docs/contributing/)! You may also want to know [how to hack on the hawtio code](DEVELOPERS.md)
+
+[hawtio](http://hawt.io/) can now be built **without** having to install node.js or anything first thanks to the [frontend-maven-plugin](https://github.com/eirslett/frontend-maven-plugin). This
+will install node.js & npm into a subdirectory, run `npm install` to install dependencies & run the build like normal.
+
+## Building
+
+After you've cloned hawtio's git repo the first thing you should do is build the whole project. First `cd` into the root directory of the hawtio project and run:
+
+ mvn clean install
+
+This will ensure all dependencies within the hawtio repo are built and any dependencies are downloaded and in your local repo.
+
+To run the sample web application for development, type:
+
+ cd hawtio-web
+ mvn compile
+ mvn test-compile exec:java
+
+On OS X and linux the _mvn compile_ command above is unnecessary but folks have found on windows there can be timing issues with grunt and maven that make this extra step a requirement (see [issue #203 for more details](https://github.com/hawtio/hawtio/issues/203#issuecomment-15808516))
+
+Or if you want to just run an empty hawtio and connect in hawtio to a remote container (e.g. connect to a Fuse Fabric or something via the Connect tab) just run
+
+ cd hawtio-web
+ mvn clean jetty:run
+
+### How to resolve building error of hawtio-web
+
+In case you get any building error of `hawtio-web`, then it may be due permission error of your local `.npm` directory. This has been known to happen for osx users. To remedy this
+
+ cd ~
+ cd .npm
+ sudo chown -R yourusernamehere *
+
+Where `yourusernamehere` is your username. This will change the file permissions of the node files so you can build the project. After this try building the hawtio source code again.
+
+### Troubleshooting
+
+This section should help you to figure out problems that you could discover when you build/compile the `hawtio` or `hawtio-web` module :
+
+1. ERROR : Can not find the binary /usr/local/bin/phantomjs
+If during the build, you get this error message
+
+````
+[INFO] Running "karma:unit" (karma) task
+[INFO] ERROR [launcher]: Cannot start PhantomJS
+[INFO] Can not find the binary /usr/local/bin/phantomjs
+[INFO] Please set env variable PHANTOMJS_BIN
+[INFO] Warning: Task "karma:unit" failed. Use --force to continue.
+[INFO]
+[INFO] Aborted due to warnings.
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD FAILURE
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 13.511 s
+[INFO] Finished at: 2015-01-30T07:30:49+01:00
+[INFO] Final Memory: 28M/317M
+[INFO] ------------------------------------------------------------------------
+[ERROR] Failed to execute goal com.github.eirslett:frontend-maven-plugin:0.0.16:grunt (grunt build) on project hawtio-web: Failed to run task: 'grunt default --no-color' failed. (error code 3) -> [Help 1]
+````
+the problem could be solved after removing & installing again phantomjs
+````
+npm uninstall phantomjs
+npm install phantomjs -g
+````
+
+
+
+### Trying Different Containers
+
+The above uses Jetty but you can try running hawtio in different containers via any of the following commands. Each of them runs the hawtio-web in a different container (with an empty JVM so no beans or camel by default).
+
+ mvn tomcat7:run
+ mvn tomcat6:run
+ mvn jboss-as:run
+ mvn jetty:run
+
+## Incrementally compiling TypeScript
+
+For a more rapid development workflow its good to use incremental compiling of TypeScript and to use LiveReload (or LiveEdit) below too.
+
+So in a **separate shell** (while keeping the above shell running!) run the following commands:
+
+ cd hawtio-web
+ mvn compile -Pwatch
+
+This will incrementally watch all the *.ts files in the src/main/webapp/app directory and recompile them into src/main/webapp/app/app.js whenever there's a change.
+
+## Incrementally compiling TypeScript inside IntelliJ (IDEA)
+
+The easiest way we've figured out how to use [IDEA](http://www.jetbrains.com/idea/) and TypeScript together is to setup an External Tool to run watchTsc; then you get (relatively) fast recompile of all the TypeScript files to a single app.js file; so you can just keep hacking code in IDEA and letting LiveReload reload your web page.
+
+* open the **Preferences** dialog
+* select **External Tools**
+* add a new one called **watchTsc**
+* select path to **mvn** as the program and **compile -Pwatch** as the program arguments
+* select **hawtio-web** as the working directory
+* click on Output Filters...
+* add a new Output Filter
+* use this regular expression
+
+```
+$FILE_PATH$\($LINE$,$COLUMN$\)\:
+```
+
+Now when you do **Tools** -> **watchTsc** you should get a output in the Run tab. If you get a compile error when TypeScript gets recompiled you should get a nice link to the line and column of the error.
+
+**Note** when you do this you probably want the Run window to just show the latest compile errors (which is usually the last couple of lines).
+
+I spotted a handy tip on [this issue](http://youtrack.jetbrains.com/issue/IDEA-74931), if you move the cursor to the end of the Run window after some compiler output has been generated - pressing keys _META_ + _end_ (which on OS X is the _fn_ and the _option/splat_ and right cursor keys) then IDEA keeps scrolling to the end of the output automatically; you don't have to then keep pressing the "Scroll to end" button ;)
+
+## Adding additional Javascript dependencies
+
+Hawtio is (finally) adopting [bower](http://bower.io/) for managing dependencies, these are automatically pulled in when building the project. It's now really easy to add third-party Javascript/CSS stuff to hawtio:
+
+* cd into 'hawtio-web', and build it
+* source 'setenv.sh' to add bower to your PATH (it's under node_modules) if you haven't installed it globally
+* run 'bower install --save some-awesome-tool'
+* run 'grunt bower wiredep' to update index.html
+* commit the change to bower.json and index.html
+
+When running in development mode be sure you've run 'grunt bower' if you see 404 errors for the bower package you've installed. This is normally done for you when running 'mvn clean install'
+
+## Using LiveReload
+
+The LiveReload support allows you to edit the code and for the browser to automatically reload once things are compiled. This makes for a much more fun and RAD development environment!!
+
+The easiest method to run with LiveReload support is to cd into the "hawtio-web" module and run the following:
+
+mvn test-compile exec:java
+
+The sample server runs an embedded LiveReload server that's all set up to look at src/main/webapp for file changes. If you don't want to load all of the sample apps because you're connecting to another JVM you don't have to:
+
+mvn test-compile exec:java -DloadApps=false
+
+
+The Live Reload server implementation is provided by [livereload-jvm](https://github.com/davidB/livereload-jvm). When using other methods to run hawtio, like "mvn jetty:run" or "mvn tomcat:run", you can run [livereload-jvm](https://github.com/davidB/livereload-jvm) directly, for example from the hawtio-web directory:
+
+ java -jar livereload-jvm-0.2.0-SNAPSHOT-onejar.jar -d src/main/webapp/ -e .*\.ts$
+
+Install the [LiveReload](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) plugin for Chrome and then enable it for the website (click the live reload icon on the right of the address bar). There is also a LiveReload plugin for Firefox, you can get it straight from the [LiveReload site](http://livereload.com).
+
+
+In another shell (as mentioned above in the "Incrementally compile TypeScript" section you probably want to auto-recompile all the TypeScript files into app.js in *another shell* via this command:
+
+ cd hawtio-web
+ mvn compile -Pwatch
+
+Enable Live Reload in your browser (open [http://localhost:8282/hawtio/](http://localhost:8282/hawtio/) then click on the Live Reload icon to the right of the location bar).
+
+Now if you change any source (HTML, CSS, TypeScript, JS library) the browser will auto reload on the fly. No more context-switching between your IDE and your browser! :)
+
+To specify a different port to run on, just override the `jettyPort` property
+
+ mvn test-compile exec:java -DjettyPort=8181
+
+### Using your build & LiveReload inside other web containers
+
+TODO - this needs updating still...
+
+The easiest way to use other containers and still get the benefits of LiveReload is to create a symbolic link to the generated hawtio-web war in expanded form, in the deploy directory in your web server.
+
+e.g. to use Tomcat7 in LiveReload mode try the following to create a symbolic link in the tomcat/webapps directory to the **hawtio-web/target/hawtio-web-1.3-SNAPSHOT** directory:
+
+ cd tomcat/webapps
+ ln -s ~/hawtio/hawtio-web/target/hawtio-web-1.3-SNAPSHOT hawtio
+
+Then use [livereload-jvm](https://github.com/davidB/livereload-jvm) manually as shown above.
+
+Now just run Tomcat as normal. You should have full LiveReload support and should not have to stop/start Tomcat or recreate the WAR etc!
+
+### Running hawtio against Kubernetes / OpenShift
+
+To try run a [local OpenShift V3 based on Kubernetes / Docker](http://fabric8.io/v2/getStarted.html) first
+
+ opeshift start
+
+Then run the following:
+
+ export KUBERNETES_MASTER=http://localhost:8080
+ mvn test-compile exec:java
+
+You should now see the Kubernetes / OpenShift console at http://localhost:8282/
+
+#### Using your build from inside Jetty
+
+For jetty you need to name the symlink directory **hawtio.war** for [Jetty to recognise it](http://www.eclipse.org/jetty/documentation/current/automatic-webapp-deployment.html).
+
+ cd jetty-distribution/webapps
+ ln -s ~/hawtio/hawtio-web/target/hawtio-web-1.3-SNAPSHOT hawtio.war
+
+Another thing is for symlinks jetty uses the real directory name rather than the symlink name for the context path.
+
+So to open the application in Jetty open [http://localhost:8282/hawtio-web-1.3-SNAPSHOT/](http://localhost:8282/hawtio-web-1.3-SNAPSHOT/)
+
+
+## Running Unit Tests
+
+You can run the unit tests via maven:
+
+ cd hawtio-web
+ mvn test
+
+If you are using the [LiveReload plugin for Chrome](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) you can then hit the LiveReload icon to the right of the address bar and if you are running the watch profile, the tests are re-run every time there is a compile:
+
+ mvn test -Pwatch
+
+Now the unit tests are all re-run whenever you edit the source.
+
+## Running integration Tests
+
+You can run the Protractor integration tests via maven:
+
+ cd hawtio-web
+ mvn verify -Pitests
+
+This will run the tests headlessly, in [Phantomjs](http://phantomjs.org/).
+
+If you want to see the tests running, you can run them in Chrome with:
+
+ cd hawtio-web
+ mvn verify -Pitests,chrome
+
+## How to Get Started Hacking the Code
+
+Check out the [hawtio technologies, tools and code walkthroughs](http://hawt.io/developers/index.html)
+
+## Trying hawtio with Fuse Fabric
+
+As of writing hawtio depends on the latest snapshot of [Fuse Fabric](http://fuse.fusesource.org/fabric/). To try out hawtio with it try these steps:
+
+ 1. Grab the latest [Fuse Fabric source code](http://fuse.fusesource.org/source.html) and do a build in the fabric directory...
+
+ git clone git://github.com/fusesource/fuse.git
+ cd fuse
+ cd fabric
+ mvn -Dtest=false -DfailIfNoTests=false clean install
+
+ 2. Now create a Fuse Fabric instance
+
+ cd fuse-fabric\target
+ tar xf fuse-fabric-99-master-SNAPSHOT.tar.gz
+ cd fuse-fabric-99-master-SNAPSHOT
+ bin/fusefabric
+
+ 3. When the Fabric starts up run the command
+
+ fabric:create
+
+ to properly test things out you might want to create a new version and maybe some child containers.
+
+### Running hawtio with Fuse Fabric in development mode
+
+ cd hawtio-web
+ mvn test-compile exec:java -Psnapshot,fabric
+
+### Running hawtio using `jetty-maven-plugin` with authentication enabled
+
+Running hawtio using `mvn jetty:run` will switch hawtio configuration to use system (instead of JNDI) properties. The default configuration uses
+`/` list inside `jetty-maven-plugin` configuration.
+
+One of those properties is standard JAAS property `java.security.auth.login.config` pointing at Jetty-Plus JAAS LoginModule which uses `src/test/resources/users.properties` file for mapping
+users to password and roles.
+
+By default this mapping is:
+
+ admin=admin123,admin,viewer
+
+However `hawtio.authenticationEnabled` is disabled (`false`) by default. So in order to run hawtio using Jetty Maven plugin with authentication enabled, you can either
+change this property in `hawtio-web/pom.xml`, or simply run:
+
+ mvn jetty:run -Dhawtio.authenticationEnabled=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/CHANGES.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/CHANGES.md"
new file mode 100755
index 0000000..bdefb01
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/CHANGES.md"
@@ -0,0 +1,93 @@
+## Change Log
+
+#### 2.6.0 (To be released)
+
+#### 2.5.0
+
+* Add config property `hawtio.localAddressProbing`. Now you can disable local address probing
+ for proxy whitelist upon startup by setting this property to `false` (default: `true`).
+* Upgrade Camel to 2.23.1
+* Upgrade Spring Framework to 5.1.3
+* Upgrade Spring Boot to 2.1.2
+* Bug fixes
+
+#### 2.4.0
+
+* Support Java 11
+* Upgrade @hawtio/integration, @hawtio/jmx to 4.2.x
+* Upgrade Spring Boot to 2.1.1
+
+#### 2.3.0
+
+* Add support for Spring Boot 2
+ **Note:** Spring Boot 2 is now the default Spring Boot version for Hawtio dependency `hawtio-spring-boot`.
+ If Spring Boot 1 is required, use dependency `hawtio-spring-boot-1`.
+* Bug fixes
+
+#### 2.2.0
+
+* Upgrade Hawtio components to 4.1.x
+* Minor improvements
+* Bug fixes
+
+#### 2.1.0
+
+* Upgrade Hawtio components to 4.0.x
+* Upgrade AngularJS to 1.7.x
+* Improve security-releated HTTP headers handling
+* Bug fixes
+
+#### 2.0.3
+
+- #2488: Allow using SSL by specifying a keyStore and keyStorePass from embedded Hawtio
+
+#### 2.0.2
+
+* **Official Hawtio v2 GA version!**
+
+#### 2.0.0, 2.0.1
+
+* These are old versions that were mistakenly released years ago. Please don't use these versions!
+
+#### 2.0 Beta3 (To be released)
+
+* Added hawtio BOM
+
+#### 2.0 Beta2
+
+* Keycloak integration support
+* Bug fixes
+
+#### 2.0 Beta1
+
+* hawtio Maven plugin
+* Improved Spring Boot support
+* Log plugin
+* Diagnostics plugin
+* Karaf RBAC support
+* PatternFly-based login page and logo
+* Upgrade to Servlet API 3.1
+* Port fixes from hawtio v1
+* Bug fixes
+
+#### 2.0 M3
+
+* Switch from bower to yarn
+* Help plugin
+* Port fixes from hawtio v1
+
+#### 2.0 M2
+
+* Migrate to PatternFly
+* Bug fixes
+* Port fixes from hawtio v1
+
+#### 2.0 M1
+
+* Initial 2.0 milestone release
+
+-----
+
+#### 1.x
+
+See: https://github.com/hawtio/hawtio/blob/1.x/CHANGES.md
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/CONTRIBUTING.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/CONTRIBUTING.md"
new file mode 100755
index 0000000..f1308d3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/CONTRIBUTING.md"
@@ -0,0 +1,62 @@
+We love contributions! We really need your help to make [hawtio](http://hawt.io/) even more hawt, so please [join our community](http://hawt.io/community/index.html)!
+
+Many thanks to all of our [existing contributors](https://github.com/hawtio/hawtio/graphs/contributors)! But we're greedy, we want more! hawtio is _hawt_, but it can be _hawter_! :). We have [lots of plugins](http://hawt.io/plugins/index.html) but they can be improved and we want more plugins!
+
+Here's some notes to help you get started:
+
+## Getting Started
+
+* Make sure you have a [GitHub account](https://github.com/signup/free) as you'll need it to submit issues, comments or pull requests.
+* Got any ideas for how we can improve hawtio? Please [submit an issue](https://github.com/hawtio/hawtio/issues?state=open) with your thoughts. Constructive criticism is always greatly appreciated!
+* Fancy submitting [any nice screenshots of how you're using hawtio?](https://github.com/hawtio/hawtio/tree/master/website/src/images/screenshots) A quick Youtube screencast would be even _hawter_ or a blog post/article we can link to? Just [submit an issue](https://github.com/hawtio/hawtio/issues?state=open) (or fork and patch the [website](https://github.com/hawtio/hawtio/tree/master/website/src/) or any Markdown docs in our repository directly) and we'll merge it into our website.
+* Fancy submitting your cool new dashboard configuration or some wiki docs? See below on how to do that...
+* Search [our issue tracker](https://github.com/hawtio/hawtio/issues?state=open) and see if there's been any ideas or issues reported for what you had in mind; if so please join the conversation in the comments.
+* Submit any issues, feature requests or improvement ideas [our issue tracker](https://github.com/hawtio/hawtio/issues?state=open).
+ * Clearly describe the issue including steps to reproduce when it is a bug.
+ * Make sure you fill in the earliest version that you know has the issue.
+
+### Fancy hacking some code?
+
+* If you fancy working on some code, check out the these lists of issues:
+ * [open apprentice tasks](https://github.com/hawtio/hawtio/issues?labels=apprentice+tasks&page=1&sort=updated&state=open) - which are moderately easy to fix and tend to have links to which bits of the code to look at to fix it or
+ * [all open issues](https://github.com/hawtio/hawtio/issues?state=open) if you fancy being more adventurous.
+ * [hawt ideas](https://github.com/hawtio/hawtio/issues?labels=hawt+ideas&page=1&sort=updated&state=open) if you're feeling like a ninja and fancy tackling our harder issues that tend to add really _hawt_ new features!
+
+* To make code changes, fork the repository on GitHub then you can hack on the code. We love any contribution such as:
+ * fixing typos
+ * improving the documentation or embedded help
+ * writing new test cases or improve existing ones
+ * adding new features
+ * improving the layout / design / CSS
+ * creating a new [plugin](http://hawt.io/plugins/index.html)
+
+## Submitting changes to hawtio
+
+* Push your changes to your fork of the [hawtio repository](https://github.com/hawtio/hawtio).
+* Submit a pull request to the repository in the **hawtio** organization.
+* If your change references an existing [issue](https://github.com/hawtio/hawtio/issues?state=open) then use "fixes #123" in the commit message (using the correct issue number ;).
+
+## Submitting changes dashboard and wiki content
+
+Hawtio uses the [hawtio-config repository](https://github.com/hawtio/hawtio-config) to host its runtime configuration. When you startup hawtio by default it will clone this repository to the configuration directory (see the [configuration document](https://github.com/hawtio/hawtio/blob/master/docs/Configuration.md) or more detail).
+
+In development mode if you are running hawtio via the **hawtio-web** directory, then your local clone of the [hawtio-config repository](https://github.com/hawtio/hawtio-config) will be in the **hawtio/hawtio-web/hawtio-config directory**. If you've added some cool new dashboard or editted any files via the hawtio user interface then your changes will be committed locally in this directory.
+
+If you are a committer and want to submit any changes back just type:
+
+ cd hawtio-config
+ git push
+
+Otherwise if you want to submit pull requests for your new dashboard or wiki content then fork the [hawtio-config repository](https://github.com/hawtio/hawtio-config) then update your hawtio-config directory to point to this directory. e.g. edit the hawtio-config/.git/config file to point to your forked repository.
+
+Now perform a git push as above and then submit a pull request on your forked repo.
+
+# Additional Resources
+
+* [FAQ](http://hawt.io/docs/faq/)
+* [General GitHub documentation](http://help.github.com/)
+* [GitHub create pull request documentation](https://help.github.com/articles/creating-a-pull-request)
+* [Here is how to build the code](BUILDING.md)
+* [More information for developers in terms of hawtio technologies, tools and code walkthroughs](DEVELOPERS.md)
+* [Join the hawtio community](http://hawt.io/community/)
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/DEVELOPERS.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/DEVELOPERS.md"
new file mode 100755
index 0000000..4685e1f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/DEVELOPERS.md"
@@ -0,0 +1,189 @@
+We love [contributions](http://hawt.io/docs/contributing/). This page is intended to help you get started hacking on the code, it contains various information on technology and tools together with code walk-throughs.
+
+Welcome and enjoy! Its hawt, but stay cool! :)
+
+## Building the code
+
+Check out [How To Build The Code](BUILDING.md) if you want to start hacking on the source.
+
+## Architecture
+
+**hawtio** is a single page application which is highly modular and capable of dynamically loading [plugins](http://hawt.io/plugins/index.html) based on the capability of the server.
+
+You may want to check out:
+
+* [Current hawtio plugins](http://hawt.io/plugins/index.html)
+* [How plugins work](http://hawt.io/docs/how-plugins-work/)
+
+## Developer Tools
+
+The following are recommended if you want to contribute to the code
+
+* [IntelliJ IDEA EAP 12 or later](http://confluence.jetbrains.net/display/IDEADEV/IDEA+12+EAP) as this has TypeScript support and is the daddy of IDEs!
+* [There are other TypeScript plugins](http://blogs.msdn.com/b/interoperability/archive/2012/10/01/sublime-text-vi-emacs-typescript-enabled.aspx) if you prefer Sublime, Emacs or VIM. (Unfortunately we're not aware of an eclipse plugin yet).
+* [AngularJS plugin for IDEA](http://plugins.jetbrains.com/plugin/?id=6971) if you use [IDEA](http://www.jetbrains.com/idea/) then this plugin really helps work with Angular JS
+* [AngularJS plugin for Chrome](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk) which is handy for visualising scopes and performance testing etc.
+* [JSONView plugin for Chrome](https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc) makes it easy to visualise JSON returned by the [REST API of Jolokia](http://jolokia.org/reference/html/protocol.html)
+* [Apache Maven 3.0.3 or later](http://maven.apache.org/)
+* [gruntjs](http://gruntjs.com/) a build tool for JavaScript. See nearly the beginning of this document for details of how to install and use.
+* [Dash.app](http://kapeli.com/) is a handy tool for browsing API documentation for JavaScript, HTML, CSS, jquery, AngularJS etc.
+
+## JavaScript Libraries
+
+For those interested in [contributing](http://hawt.io/contributing/index.html) or just learning how to build single page applications, here is a list of the various open source libraries used to build hawtio:
+
+* [AngularJS](http://angularjs.org/) is the web framework for performing real time two-way binding of HTML to the model of the UI using simple declarative attributes in the HTML.
+* [jolokia](http://jolokia.org/) is the server side / JVM plugin for exposing JMX as JSON over HTTP. It's awesome and is currently the only server side component of hawtio.
+* [TypeScript](http://typescriptlang.org/) is the language used to implement the console; it compiles to JavaScript and adds classes, modules, type inference & type checking. We recommend [IntelliJ IDEA EAP 12 or later](http://confluence.jetbrains.net/display/IDEADEV/IDEA+12+EAP) for editing TypeScript--especially if you don't use Windows or Visual Studio (though there is a Sublime Text plugin too).
+* [angular ui](http://angular-ui.github.com/) is a library of AngularJS additions and directives
+* [d3](http://d3js.org/) is the visualization library used to do the force layout graphs (for example the diagram view for ActiveMQ)
+* [cubism](http://square.github.com/cubism/) implements the real-time horizon charts
+* [dagre](https://github.com/cpettitt/dagre) for graphviz style layouts of d3 diagrams (e.g. the Camel diagram view).
+* [ng-grid](http://angular-ui.github.com/ng-grid/) an AngualrJS based table/grid component for sorting/filtering/resizing tables
+* [marked](https://github.com/chjj/marked) for rendering Github-flavoured Markdown as HTML
+* [DataTables](http://datatables.net/) for sorted/filtered tables (though we are migrating to ng-grid as its a bit more natural for AngularJS)
+* [DynaTree](http://wwwendt.de/tech/dynatree/doc/dynatree-doc.html) for tree widget
+* [jQuery](http://jquery.com/) small bits of general DOM stuff, usually when working with third-party libraries which don't use AngularJS
+* [Twitter Bootstrap](http://twitter.github.com/bootstrap/) for CSS
+* [Toastr](https://github.com/CodeSeven/toastr) for notifications
+
+We're not yet using it but these look handy too:
+
+* [jquery-mobile-angular-adapter](https://github.com/tigbro/jquery-mobile-angular-adapter) for easy interop of jQuery Mobile and AngularJS
+* [breezejs](http://www.breezejs.com/) for easy LINQ / ActiveRecord style database access and synchronization
+
+## API documentation
+
+If you are interested in working on the code the following references and articles have been really useful so far:
+
+* [available AngularJS Directives](http://hawt.io/developers/directives.html)
+* [angularjs API](http://docs.angularjs.org/api/)
+* [bootstrap API](http://twitter.github.com/bootstrap/base-css.html)
+* [cubism API](https://github.com/square/cubism/wiki/API-Reference)
+* [d3 API](https://github.com/mbostock/d3/wiki/API-Reference)
+* [ng-grid API](http://angular-ui.github.com/ng-grid/#/api)
+* [datatables API](http://www.datatables.net/api)
+* [javascript API](http://www.w3schools.com/jsref/default.asp)
+* [sugarjs API](http://sugarjs.com/api/Array/sortBy)
+* [icons from Font Awesome](http://fortawesome.github.com/Font-Awesome/)
+
+### Developer Articles, Forums and Resources
+
+* [Fun with AngularJS](http://devgirl.org/2013/03/21/fun-with-angularjs/) is great overview on AngularJS!
+* [egghead.io various short angularjs videos](http://egghead.io/)
+* [great angularjs talk](http://www.youtube.com/angularjs)
+* [AngularJS plugins](http://ngmodules.org/)
+* [AngularJS tips and tricks](http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED)
+* [more AngularJS magic to supercharge your webapp](http://www.yearofmoo.com/2012/10/more-angularjs-magic-to-supercharge-your-webapp.html#)
+* [AngularJS questions on stackoverflow](http://stackoverflow.com/questions/tagged/angularjs)
+* [Modeling Data and State in Your AngularJS Application](http://joelhooks.com/blog/2013/04/24/modeling-data-and-state-in-your-angularjs-application/)
+* [6 Common Pitfalls Using Scopes](http://thenittygritty.co/angularjs-pitfalls-using-scopes)
+
+## Code Walkthrough
+
+If you fancy contributing--and [we love contributions!](http://hawt.io/docs/contributing/)--the following should give you an overview of how the code hangs together:
+
+* hawtio is a single page web application, from [this single page of HTML](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/index.html)
+* We use [AngularJS routing](http://docs.angularjs.org/api/ng.directive:ngView) to display different [partial pages](https://github.com/hawtio/hawtio/tree/master/hawtio-web/src/main/webapp/app/core/html) depending on which tab/view you choose. You'll notice that the partials are simple HTML fragments which use [AngularJS](http://angularjs.org/) attributes (starting with **ng-**) along with some {{expressions}} in the markup.
+* Other than the JavaScript libraries listed above which live in [webapp/lib](https://github.com/hawtio/hawtio/tree/master/hawtio-web/src/main/webapp/lib) and are [included in the index.html](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/index.html), we then implement [AngularJS](http://angularjs.org/) controllers using [TypeScript](http://typescriptlang.org/). All the typescript source is in the [in files in webapp/app/pluginName/js/ directory](https://github.com/hawtio/hawtio/tree/master/hawtio-web/src/main/webapp/app) which is then compiled into the [webapp/app/app.js file](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/app.js)
+* To be able to compile with TypeScript's static type checking we use the various [TypeScript definition files](https://github.com/hawtio/hawtio/tree/master/hawtio-web/src/main/d.ts) to define the optional statically typed APIs for the various APIs we use
+* The controllers use the [Jolokia JavaScript API](http://jolokia.org/reference/html/clients.html#client-javascript) to interact with the server side JMX MBeans
+
+### How the Tabs Work
+
+Tabs can dynamically become visible or disappear based on the following:
+
+* the contents of the JVM
+* the [plugins](http://hawt.io/docs/plugins/),
+* and the current UI selection(s).
+
+[Plugins](http://hawt.io/docs/plugins/) can register new top-level tabs by adding to the [topLevelTabs](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/log/js/logPlugin.ts#L9) on the workspace which can be dependency injected into your plugin via [AngularJS Dependency Injection](http://docs.angularjs.org/guide/di).
+
+The [isValid()](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/log/js/logPlugin.ts#L12) function is then used to specify when this top-level tab should be visible.
+
+You can register [subLevelTabs](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/log/js/logPlugin.ts#L16) which are then visible when the [right kind of MBean is selected](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/log/js/logPlugin.ts#L19).
+
+For more detail check out the [plugin documentation](http://hawt.io/docs/plugins/).
+
+#### Enable Source Maps for Easier Debugging
+
+We recommend you enable [Source Maps](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1) in your browser (e.g. in Chrome) for easier debugging by clicking on the bottom-right Settings icon in the *JavaScript Console* and [enabling Source Maps support such as in this video](http://www.youtube.com/watch?v=-xJl22Kvgjg).
+
+#### Notes on Using IDEA
+
+To help IDEA navigate to functions in your source and to avoid noise, you may want to ignore some JavaScript files in IDEA so that they are not included in the navigation. Go to `Settings/Preferences -> File Types -> Ignore Files` then add these patterns to the end:
+
+ *.min.js;*-min.js
+
+Ignoring these files will let IDEA ignore the minified versions of the JavaScript libraries.
+
+Then select the generated [webapp/app/app.js file](https://github.com/hawtio/hawtio/blob/master/hawtio-web/src/main/webapp/app/app.js) in the Project Explorer, right-click and select _Mark as Plain Text_ so that it is ignored as being JavaScript source. This hint came from [this forum thread](http://devnet.jetbrains.net/message/5472690#5472690), hopefully there will be a nicer way to do all this one day!
+
+#### Handy AngularJS debugging tip
+
+Open the JavaScript Console and select the _Console_ tab so you can type expressions into the shell.
+Select part of the DOM of the scope you want to investigate
+Right click and select _Inspect Element_
+In the console type the following
+
+ s = angular.element($0).scope()
+
+You have now defined a variable called _s_ which contains all the values in the active AngularJS scope so you can navigate into the scope and inspect values or invoke functions in the REPL, etc.
+
+#### Handy JQuery debugging tip
+
+Open the JavaScript Console and select the _Console_ tab so you can type expressions into the shell.
+Select a DOM element (e.g., button) for which you want to check what jquery event handlers are attached.
+In the console type:
+
+ jQuery._data($0, "events")
+
+You'll get array of events. When you expand the events and go to "handler" member (e.g., `click->0->handler`), you can:
+
+* in Firebug right click `function()` and select _Inspect in Script Panel_
+* in Chrome dev tools right click `function()` and select _Show Function Definition_
+
+to see the body of handler method.
+
+### Handy AngularJS programming tips
+
+#### Use a nested scope object to own state for 2 way binding
+
+When binding models to HTML templates; its always a good idea to use a level of indirection between the $scope and the property. So rather than binding to $scope.name, bind to $scope.entity.name then have code like
+
+ $scope.entity = { "name": "James" };
+
+This means to that to reset the form you can just do
+
+ $scope.entity = {};
+
+And you can then refer to the entire entity via **$scope.entity**. Another reason for doing this is that when you have lots of nested scopes; for example when using nested directives, or using includes or layouts, you don't get inheritence issues; since you can acess $scope.entity from child scopes fine.
+
+#### When working with $routeParams use the $scope.$on
+
+Its often useful to use $routeParams to get the URI template parameters. However due to [the rules on who gets the $routeParams injected](http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED#routing) when using layouts and so forth, the $routeParams can be empty.
+
+So put all code that uses $routeParams inside the $routeChangeSuccess callback:
+
+ $scope.$on('$routeChangeSuccess', function(event, routeData){
+ // process $routeParams now...
+ });
+
+### Local Storage
+
+hawtio uses local storage to store preferences and preferred views for different kinds of MBean type and so forth.
+
+You can view the current Local Storage in the Chrome developer tools console in the Resources / Local Storage tab.
+
+If you ever want to clear it out in Chrome on OS X you'll find this located at `~/Library/Application Support/Google/Chrome/Default/Local Storage`.
+
+
+### Updating the hawtio website
+
+The website is automatic build and updated on each commit. There is a CI job on circleci that runs
+
+ https://circleci.com/gh/hawtio/hawtio
+
+The task runs the script `ci-website.sh` that builds the website. If anything goes wrong, the errors are usually shown in the CI job output (link above).
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/FAQ.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/FAQ.md"
new file mode 100755
index 0000000..c72671a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/FAQ.md"
@@ -0,0 +1,222 @@
+## General Questions
+
+General questions on all things hawtio.
+
+#### What is the license?
+
+hawtio uses the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.txt).
+
+#### What does hawtio do?
+
+It's a [pluggable](http://hawt.io/plugins/index.html) management console for Java stuff which supports any kind of JVM, any kind of container (Tomcat, Jetty, Karaf, JBoss, Fuse Fabric, etc), and any kind of Java technology and middleware.
+
+#### How do I install hawtio?
+
+See the [Getting Started Guide](http://hawt.io/getstarted/index.html) and the [Configuration Guide](http://hawt.io/configuration/index.html)
+
+#### How do I configure hawtio?
+
+Mostly hawtio just works. However, please check out the [Configuration Guide](http://hawt.io/configuration/index.html) to see what kinds of things you can configure via system properties, environment variables, web.xml context-params or dependency injection.
+
+#### How do I disable security?
+
+Since 1.2-M2 of hawtio we enable security by default using the underlying application container's security mechanism.
+
+Here's how to [disable security](https://github.com/hawtio/hawtio/blob/master/docs/Configuration.md#configuring-or-disabling-security-in-karaf-servicemix-fuse) if you wish to remove the need to login to hawtio.
+
+#### Which Java version is required?
+
+- Hawtio 1.5 onwards - requires Java 8.
+- Hawtio 1.4 - requires Java 7 or 8.
+- Hawtio 1.3 or older - supports Java 6 and 7.
+
+#### How do I enable hawtio inside my Java Application / Spring Boot / DropWizard / Micro Service
+
+The easiest thing to do is add jolokia as a java agent via a java agent command line:
+
+ java -javaagent:jolokia-agent.jar=host=0.0.0.0 -jar foo.jar
+
+Then by default you can connect on http;//localhost:8778/jolokia to access the jolokia REST API.
+
+Now you can use hawtio (e.g. the Google Chrome Extension or the stand alone hawtio application) to connect to it - and it then minimises the effect of hawtio/jolokia on your app (e.g. you don't need to mess about with whats inside your application or even change the classpath)
+
+#### How do I connect to my remote JVM?
+
+All that's required for hawtio to connect to any remote JVM is that a [jolokia agent](http://jolokia.org/agent.html) is attached to the JVM you wish to connect to. This can be done in various ways.
+
+Firstly if you are using [Fuse](http://www.jboss.org/products/fuse) or [Apache ActiveMQ 5.9.x or later](http://activemq.apache.org/) then you already have jolokia enabled by default.
+
+If a JVM has no jolokia agent, you can use the **Local** tab of the **Connect** menu (in 1.2.x or later of **hawtio-default.war**). The Local tab lists all local Java processes on the same machine (just like JConsole does).
+
+For JVMs not running a jolokia agent already, there's a start button (on the right) which will dynamically add the [jolokia JVM agent](http://jolokia.org/agent/jvm.html) into the selected JVM process. You can then click on the Agent URL link to connect into it.
+
+Note that the Local plugin only works when the JVM running hawtio has the **hawtio-local-jvm-mbean** plugin installed (which depends on the JVM finding the com.sun.tools.attach.VirtualMachine API that jconsole uses and is included in the hawtio-default.war). BTW if you don't see a **Local** tab inside the **Conect** menu in your hawtio application; check the log of your hawtio JVM; there might be a warning around com.sun.tools.attach.VirtualMachine not being available on the classpath. Or you could just try using the [exectuable jar](http://hawt.io/getstarted/index.html) to run hawtio which seems to work on most platforms.
+
+Note also that the **Local** tab only works when the process is on the same machine as the JVM running hawtio. So a safer option is just to make sure there's a jolokia agent running in each JVM you want to manage with hawtio.
+
+There are a [few different agents you can use](http://jolokia.org/agent.html):
+
+* [WAR agent](http://jolokia.org/agent/war.html) if you are using a servlet / EE container
+* [OSGi agent](http://jolokia.org/agent/osgi.html) if you are using OSGi (note that Jolokia is enabled by default in [Fuse](http://www.jboss.org/products/fuse) so you don't have to worry)
+* [JVM agent](http://jolokia.org/agent/jvm.html) if you are using a stand alone Java process
+
+So once you've got a jolokia agent in your JVM you can test it by accessing `http://host:port/jolokia` in a browser to see if you can view the JSON returned for the version information of the jolokia agent.
+
+Assuming you have jolokia working in your JVM, then you can use the **Remote** tab on the **Connect** menu in hawtio to connect; just enter the host, port, jolokia path and user/password. Note by default only `localhost` is accepted to connect for security, so you need to configure `hawtio.proxyWhitelist` system property or `proxyWhitelist` init parameter on `ProxyServlet` in `hawtio.war`'s `WEB-INF/web.xml` to explicitly allow hosts that you are connecting to.
+
+After trying the above if you have problems connecting to your JVM, please [let us know](http://hawt.io/community/index.html) by [raising an issue](https://github.com/hawtio/hawtio/issues?state=open) and we'll try to help.
+
+#### How do I install a plugin?
+
+Each hawtio distro has these [browser based plugins](http://hawt.io/plugins/index.html) inside already; plus hawtio can discover any other external plugins deployed in the same JVM too.
+
+Then the hawtio UI updates itself in real time based on what it can find in the server side JVM it connects to. So, for example, if you connect to an empty tomcat/jetty you'll just see things like JMX and tomcat/jetty (and maybe wiki / dashboard / maven if you're using hawtio-default.war which has a few more server side plugins inside).
+
+Then if you deploy a WAR which has ActiveMQ or Camel inside it, you should see an ActiveMQ or Camel tab appear as you deploy code which registers mbeans for ActiveMQ or Camel.
+
+So usually, if you are interested in a particular plugin and its not visible in the hawtio UI (after checking your preferences in case you disabled it), usually you just need to deploy or add a server side plugin; which is usually a case of deploying some Java code (e.g. ActiveMQ, Camel, Infinispan etc).
+
+#### What has changed lately?
+
+Try have a look at the [change log](http://hawt.io/changelog.html) to see the latest changes in hawtio!
+
+#### Where can I find more information?
+
+Try have a look at the [articles and demos](http://hawt.io/articles/index.html) to see what other folks are saying about hawtio.
+
+#### Why does hawtio log a bunch of 404s to the javascript console at startup?
+
+The hawtio help registry tries to automatically discover help data for each registered plugin even if plugins haven't specifically registered a help file.
+
+#### Why does hawtio have its own wiki?
+
+At first a git-based wiki might not seem terribly relevant to hawtio. A wiki can be useful to document running systems and link to the various consoles, operational tools and views. Though in addition to being used for documentation, hawtio's wiki also lets you view and edit any text file; such as Camel routes, Fuse Fabric profiles, Spring XML files, Drools rulebases, etc.
+
+From a hawtio perspective though its wiki pages can be HTML or Markdown and then be an AngularJS HTML partial. So it can include JavaScript widgets; or it can include [AngularJS directives](http://docs.angularjs.org/guide/directive).
+
+This lets us use HTML and Markdown files to define custom views using HTML directives (custom tags) from any [hawtio plugins](http://hawt.io/plugins/index.html). Hopefully over time we can build a large library of HTML directives that folks can use inside HTML or Markdown files to show attribute values or charts from MBeans in real time, to show a panel from a dashboard, etc. Then folks can make their own mashups and happy pages showing just the information they want.
+
+So another way to think of hawtio wiki pages is as a kind of plugin or a custom format of a dashboard page. Right now each dashboard page assumes a grid layout of rectangular widgets which you can add to and then move around. However with a wiki page you can choose to render whatever information & widgets you like in whatever layout you like. You have full control over the content and layout of the page!
+
+Here are some [sample](https://github.com/hawtio/hawtio/issues/103) [issues](https://github.com/hawtio/hawtio/issues/62) on this if you want to help!
+
+So whether the hawtio wiki is used for documentation, to link to various hawtio and external resources, to create custom mashups or happy pages or to provide new plugin views--all the content of the wiki is audited, versioned and stored in git so it's easy to see who changed what, when and to roll back changes, etc.
+
+#### How to I install hawtio as web console for Apache ActiveMQ
+
+You can use hawtio to remote manage any ActiveMQ brokers without the need to co-install hawtio together with the ActiveMQ broker. However you can also install hawtio with the broker if you want. Dejan Bosanac [blogged how to do this](http://sensatic.net/activemq/activemq-and-hawtio.html).
+
+
+### Problems/General Questions about using hawtio
+
+Questions relating to errors you get while using hawtio or other general questions:
+
+#### How can I hide or move tabs to different perspectives?
+
+An easy way is to use a plugin to reconfigure the default perspective definition. Have a look at the [custom-perspective](https://github.com/hawtio/hawtio/tree/master/hawtio-plugin-examples/custom-perspective) for a plugin-based solution.
+
+From **hawtio 1.2.2** onwards you can reorder and hide plugins from the preference.
+
+
+#### Provider sun.tools.attach.WindowsAttachProvider could not be instantiated: java.lang.UnsatisfiedLinkError: no attach in java.library.path
+
+If you see an error like this:
+
+ java.util.ServiceConfigurationError: com.sun.tools.attach.spi.AttachProvider: Provider sun.tools.attach.WindowsAttachProvider could not be instantiated: java.lang.UnsatisfiedLinkError: no attach in java.library.path
+
+when starting up or trying the **Connect/Local** tab then its probably related to [this issue](http://stackoverflow.com/questions/14027164/fix-the-java-lang-unsatisfiedlinkerror-no-attach-in-java-library-path) as was found on [#718](https://github.com/hawtio/hawtio/issues/718#issuecomment-27677738).
+
+Basically you need to make sure that you have JAVA_HOME/bin on your path. e.g. try this first before starting hawtio:
+
+ set path=%path%;%JAVA_HOME%\jre\bin
+
+#### The Terminal plugin in Karaf does not work
+
+The terminal plugin may have trouble the first time in use, not being able to connect and show the terminal. Try selecting another plugin, and go back to the terminal plugin a bit later, and it then may be able to login. Also if the screen is all black, then pressing ENTER may help show the terminal.
+
+
+#### Why does the Camel Route Diagram not show counters
+
+If you use Apache ServixeMix / Karaf and you deploy a Camel XML file by copying a xml file to the deploy directory, then the deployer does not run this with proper security. So the Karaf RBAC will deny the Apache Camel plugin to query the Camel routes to gather performance counters. As deploying by using plain XML files is not recommended, then it works by using a deployment unit as a proper OSGi bundle such as a JAR or KAR file.
+
+
+#### The tree keeps refreshing making the UI sluggish
+
+The reason is that there is something running in the JVM that keeps modifying the JMX tree, such as repeativily adding/removing same set of MBeans. For example Apache ActiveMQ does that when a JMS Client has been mis configured or configured without a connection pool. Because of no connection pool, then ActiveMQ JMS client creates a new connection, uses and closes the connection, and repeat that. As a net result of that, the MBean tree keeps being modified, which causes Hawtio to trigger a tree refresh. To resolve this use connection pooling with ActiveMQ - which you should always do. For an example see [issue 1903](https://github.com/hawtio/hawtio/issues/1903) for more details and how to resolve that.
+
+
+### Plugin Questions
+
+Questions on using the available plugins:
+
+#### What plugins are available?
+
+See the list of [hawtio plugins](http://hawt.io/plugins/index.html)
+
+#### What is a plugin?
+
+See [How Plugins Work](http://hawt.io/plugins/howPluginsWork.html)
+
+
+#### Why does the OSGi tab not appear on GlassFish?
+
+This is a [reported issue](https://github.com/hawtio/hawtio/issues/158). It turns out that the standard OSGi MBeans (in the osgi.core domain) are not installed by default on GlassFish.
+
+The workaround is to install the [Gemini Management bundle](http://www.eclipse.org/gemini/management/) then you should see the MBeans in the osgi.core domain in the JMX tree; then the OSGi tab should appear!
+
+
+### Camel Questions
+
+Questions on using [Apache Camel](http://camel.apache.org/) and hawtio.
+
+#### The Camel plugin is not visible or does not show any Camels
+
+The Camel plugin currently requires that the Camel MBeans are stored using the default domain name which is `org.apache.camel`. So if you configure Camel to use a different name, using the `mbeanObjectDomainName` configuration, then the Camel plugin will not work. See details reported in ticket [1712](https://github.com/hawtio/hawtio/issues/1712).
+
+#### Why does the Debug or Trace tab not appear for my Camel route?
+
+The Debug and Trace tabs depend on the JMX MBeans provided by the Camel release you use.
+
+* the Debug tab requires at least version 2.12.x or later of your Camel library to be running
+* the Trace tab requires either a 2.12.x or later distro of Camel or a Fuse distro of Camel from about 2.8 or later
+
+
+### Developer Questions
+
+Questions on writing new plugins or hacking on existing ones:
+
+#### How do I build the project?
+
+If you just want to run hawtio in a JVM then please see the [Getting Started](http://hawt.io/getstarted/index.html) section.
+
+If you want to hack the source code then check out [how to build hawtio](http://hawt.io/building/index.html).
+
+#### What code conventions do you have?
+
+Check out the [Coding Conventions](https://github.com/hawtio/hawtio/blob/master/docs/CodingConventions.md) for our recommended approach.
+
+#### What can my new plugin do?
+
+Anything you like :). So long as it runs on a web browser, you're good to go. Please start [contributing](http://hawt.io/contributing/index.html)!
+
+#### Do I have to use TypeScript?
+
+You can write hawtio plugins in anything that runs in a browser and ideally compiles to JavaScript. So use pure JavaScript, CoffeeScript, EcmaScript6-transpiler, TypeScript, GWT, Kotlin, Ceylon, ClojureScript, ScalaJS and [any language that compiles to JavaScript](https://github.com/jashkenas/coffeescript/wiki/List-of-languages-that-compile-to-JS).
+
+So take your pick; the person who creates a plugin can use whatever language they prefer, so please contribute a [new plugin](http://hawt.io/contributing/index.html) :).
+
+The only real APIs a plugin needs to worry about are AngularJS (if you want to work in the core layout rather than just be an iframe), JSON (for some pretty trivial extension points such as adding new tabs), HTML and CSS.
+
+#### How can I add my new plugin?
+
+Check out [how plugins work](http://hawt.io/plugins/index.html). You can then either:
+
+* Fork this project and submit your plugin by [creating a Github pull request](https://help.github.com/articles/creating-a-pull-request) then we'll include your plugin by default in the hawtio distribution.
+* Make your own WAR with your plugin added (by depending on the hawtio-web.war in your pom.xml)
+* Host your plugin at some canonical website (e.g. with Github pages) then [submit an issue](https://github.com/hawtio/hawtio/issues?state=open) to tell us about it and we can add it to the plugin registry JSON file.
+
+#### How can I reuse those awesome AngularJS directives in my application?
+
+We hope that folks can just write plugins for hawtio to be able to reuse all the various [plugins](http://hawt.io/plugins/index.html) in hawtio.
+
+However if you are writing your own stand alone web application using AngularJS then please check out the [Hawtio Directives](http://hawt.io/directives/) which you should be able to reuse in any AngularJS application
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/LICENSE.txt" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/LICENSE.txt"
new file mode 100755
index 0000000..7a4a3ea
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/LICENSE.txt"
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/README.md"
new file mode 100755
index 0000000..8640ad3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/README.md"
@@ -0,0 +1,33 @@
+![hawtio][logo]
+
+[](https://circleci.com/gh/hawtio/hawtio)
+
+Don't cha wish your console was [hawt like me?](http://www.youtube.com/watch?v=YNSxNsr4wmA) I'm hawt so you can stay cool
+
+**[hawtio](http://hawt.io)** is a lightweight and [modular](http://hawt.io/docs/plugins/) HTML5 web console with [lots of plugins](http://hawt.io/docs/plugins/) for managing your Java stuff
+
+[View Demos](http://hawt.io/docs/articles/)
+[Get Started Now!](http://hawt.io/docs/get-started/)
+
+**hawtio** has [lots of plugins](http://hawt.io/docs/plugins/) such as: a git-based Dashboard and Wiki, [logs](http://hawt.io/plugins/logs/index.html), [health](http://hawt.io/plugins/health/index.html), JMX, OSGi, [Apache ActiveMQ](http://activemq.apache.org/), [Apache Camel](http://camel.apache.org/), [Apache OpenEJB](http://openejb.apache.org/), [Apache Tomcat](http://tomcat.apache.org/), [Jetty](http://www.eclipse.org/jetty/), [JBoss](http://www.jboss.org/jbossas) and [Fuse Fabric](http://fuse.fusesource.org/fabric/)
+
+You can dynamically [extend hawtio with your own plugins](http://hawt.io/docs/plugins/) or automatically [discover plugins](http://hawt.io/docs/plugins/) inside the JVM.
+
+The only server side dependency (other than the static HTML/CSS/JS/images) is the excellent [Jolokia library](http://jolokia.org) which has small footprint (around 300Kb) and is available as a [JVM agent](http://jolokia.org/agent/jvm.html), or comes embedded as a servlet inside the **hawtio-default.war** or can be deployed as [an OSGi bundle](http://jolokia.org/agent/osgi.html).
+
+
+## Want to hack on some code?
+
+We love [contributions](http://hawt.io/docs/contributing/)!
+
+* [Articles and Demos](http://hawt.io/docs/articles/)
+* [FAQ](http://hawt.io/docs/faq/)
+* [Change Log](CHANGES.md)
+* [How to contribute](http://hawt.io/docs/contributing/)
+* [How to build the code](BUILDING.md)
+* [How to get started working on the code](DEVELOPERS.md)
+* [Community](http://hawt.io/community/)
+
+Check out our [huboard](https://huboard.com/hawtio/hawtio#/) for prioritizing issues.
+
+[logo]: http://hawt.io/images/hawtio_logo.svg "hawtio"
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/bin/release" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/bin/release"
new file mode 100755
index 0000000..cd5199b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/bin/release"
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+if [ -z $2 ]; then
+ echo "Usage: `basename $0` [path to m2 settings file]"
+ exit
+fi
+
+RELEASE_VERSION=$1
+SNAPSHOT_VERSION=$2
+M2_SETTINGS=${3:-$HOME/.m2/settings.xml}
+
+echo ============================================================================
+echo Building version $RELEASE_VERSION
+echo ============================================================================
+
+mvn -s $M2_SETTINGS \
+ org.apache.maven.plugins:maven-release-plugin:2.5:prepare \
+ -Prelease \
+ -Dtag=hawtio-$RELEASE_VERSION \
+ -DreleaseVersion=$RELEASE_VERSION \
+ -DdevelopmentVersion=$SNAPSHOT_VERSION
+
+mvn -s $M2_SETTINGS \
+ org.apache.maven.plugins:maven-release-plugin:2.5:perform -Prelease
+
+git push --tags
+
+REPO_ID=$(mvn org.sonatype.plugins:nexus-staging-maven-plugin:1.6.5:rc-list -DserverId=oss-sonatype-staging -DnexusUrl=https://oss.sonatype.org | grep OPEN | grep -Eo 'iohawt-[[:digit:]]+')
+echo ============================================================================
+echo REPO_ID = $REPO_ID
+echo ============================================================================
+
+mvn -s $M2_SETTINGS \
+ org.sonatype.plugins:nexus-staging-maven-plugin:1.6.5:rc-close \
+ -DserverId=oss-sonatype-staging \
+ -DnexusUrl=https://oss.sonatype.org \
+ -DstagingRepositoryId=$REPO_ID \
+ -Ddescription="$RELEASE_VERSION is ready" \
+ -DstagingProgressTimeoutMinutes=60
+
+mvn -s $M2_SETTINGS \
+ org.sonatype.plugins:nexus-staging-maven-plugin:1.6.5:rc-release \
+ -DserverId=oss-sonatype-staging \
+ -DnexusUrl=https://oss.sonatype.org \
+ -DstagingRepositoryId=$REPO_ID \
+ -Ddescription="$RELEASE_VERSION is ready" \
+ -DstagingProgressTimeoutMinutes=60
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/bom/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/bom/pom.xml"
new file mode 100755
index 0000000..fec98bd
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/bom/pom.xml"
@@ -0,0 +1,111 @@
+
+
+ 4.0.0
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ hawtio-bom
+ pom
+ ${project.artifactId}
+ hawtio :: BOM
+
+
+
+
+ io.hawt
+ hawtio-app
+ ${project.version}
+
+
+ io.hawt
+ hawtio-base
+ ${project.version}
+
+
+ io.hawt
+ hawtio-console-assembly
+ ${project.version}
+
+
+ io.hawt
+ hawtio-core
+ ${project.version}
+
+
+ io.hawt
+ hawtio-default
+ ${project.version}
+
+
+ io.hawt
+ hawtio-embedded
+ ${project.version}
+
+
+ io.hawt
+ hawtio-ide
+ ${project.version}
+
+
+ io.hawt
+ hawtio-karaf
+ ${project.version}
+
+
+ io.hawt
+ hawtio-log
+ ${project.version}
+
+
+ io.hawt
+ hawtio-log-osgi
+ ${project.version}
+
+
+ io.hawt
+ hawtio-local-jvm-mbean
+ ${project.version}
+
+
+ io.hawt
+ hawtio-osgi-jmx
+ ${project.version}
+
+
+ io.hawt
+ hawtio-springboot
+ ${project.version}
+
+
+ io.hawt
+ hawtio-springboot-1
+ ${project.version}
+
+
+ io.hawt
+ hawtio-system
+ ${project.version}
+
+
+ io.hawt
+ hawtio-util
+ ${project.version}
+
+
+ io.hawt
+ hawtio-war
+ ${project.version}
+
+
+ io.hawt
+ hawtio-wildfly
+ ${project.version}
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/README.md"
new file mode 100755
index 0000000..71d827f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/README.md"
@@ -0,0 +1,171 @@
+# Hawtio integration with Keycloak
+
+Hawtio's Keycloak integration is provided through [hawtio-oauth](https://github.com/hawtio/hawtio-oauth).
+
+Those steps assume that you want your Hawtio console to be secured by [Keycloak](http://www.keycloak.org). Integration consists of 2 main steps:
+
+1. Prepare Keycloak server
+2. Deploy Hawtio to your favourite server (Spring Boot, WildFly, Karaf, Jetty, Tomcat, Red Hat Fuse, ...) and configure it to use Keycloak for authentication
+
+
+## Table of contents
+
+1. [Prepare Keycloak server](#prepare-keycloak-server)
+2. [Apache Karaf or Red Hat Fuse](#apache-karaf-or-red-hat-fuse)
+3. [WildFly or JBoss EAP](#wildfly-or-jboss-eap)
+4. [Jetty](#jetty)
+5. [Tomcat](#tomcat)
+
+
+## Prepare Keycloak server
+
+1. Install and run Keycloak server. The easiest way is to use [Docker image](https://hub.docker.com/r/jboss/keycloak/):
+
+ $ docker run -d -p 18080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin --name keycloak jboss/keycloak
+
+ Here we use port number `18080` for Keycloak server to avoid conflict with the default port number of most application servers.
+
+2. Import [hawtio-demo-realm.json](https://github.com/hawtio/hawtio-oauth/blob/master/test-plugins/hawtio-demo-realm.json) into your Keycloak. To do that, go to the Keycloak admin console (http://localhost:18080/auth/admin/) and select "Add realm" and then select the JSON file. It creates `hawtio-demo` realm.
+
+`hawtio-demo` realm has `hawtio-client` application installed as public client. There are a couple of realm roles like `admin` and `viewer`. Names of these roles are the same as default Hawtio roles, which are allowed to login into Hawtio admin console and to JMX.
+
+There are also 3 users:
+
+* `admin` with password `admin` and role `admin`, who is allowed to login into Hawtio
+* `viewer` with password `viewer` and role `viewer`, who is allowed to login into Hawtio
+* `jdoe` with password `password` and no role assigned, who is not allowed to login into Hawtio
+
+
+## Apache Karaf or Red Hat Fuse
+
+Assume `$KARAF_HOME` is the root directory of your Karaf/Fuse installation.
+
+* Run Karaf/Fuse:
+
+ cd $KARAF_HOME/bin
+ ./karaf
+
+ Replace `./karaf` with `./fuse` if you are on Red Hat Fuse.
+
+* Install Hawtio:
+
+ feature:add-repo hawtio 2.0-beta-2
+ feature:install hawtio
+
+* Install [pax-keycloak](https://github.com/ops4j/org.ops4j.pax.keycloak):
+
+ feature:add-repo pax-keycloak
+ feature:install pax-keycloak
+
+ This automatically generates `keycloak-hawtio.json`, `keycloak-bearer.json`, and `keycloak-direct-access.json` files under `$KARAF_HOME/etc/`. It also updates `$KARAF_HOME/etc/system.properties` with the following system properties:
+
+ # Hawtio / Keycloak integration
+ hawtio.keycloakEnabled = true
+ hawtio.roles = admin,manager,viewer
+ hawtio.realm = karaf
+ hawtio.keycloakClientConfig = file://${karaf.etc}/keycloak-hawtio.json
+ hawtio.rolePrincipalClasses=org.keycloak.adapters.jaas.RolePrincipal,org.apache.karaf.jaas.boot.principal.RolePrincipal
+
+* Replace them with [keycloak-hawtio.json](keycloak-hawtio.json), [keycloak-bearer.json](keycloak-bearer.json), and [keycloak-direct-access.json](keycloak-direct-access.json) in this example. File `keycloak-bearer.json` is currently used for adapters on server (JAAS Login module) side. File `keycloak-hawtio.json` is used on client (Hawtio JS application) side. File `keycloak-direct-access.json` is not used but the realm name needs to be updated.
+
+ cp examples/keycloak-integration/keycloak-hawtio.json $KARAF_HOME/etc/
+ cp examples/keycloak-integration/keycloak-bearer.json $KARAF_HOME/etc/
+ cp examples/keycloak-integration/keycloak-direct-access.json $KARAF_HOME/etc/
+
+* Restart Karaf/Fuse.
+
+* Go to http://localhost:8181/hawtio and login to Keycloak as `admin` or `viewer` to see Hawtio admin console. If you login as `jdoe`, you should receive "forbidden" error in Hawtio.
+
+
+## WildFly or JBoss EAP
+
+Assume `$JBOSS_HOME` is the root directory of your WildFly/JBoss EAP installation and you deployed Hawtio WAR to it as described in [hawtio Get Started](http://hawt.io/getstarted/index.html).
+
+* Install Keycloak adapter subsystem to your WildFly as described on: http://www.keycloak.org/docs/3.4/securing_apps/index.html#_jboss_adapter
+
+* Download and copy [keycloak-hawtio.json](keycloak-hawtio.json) and [keycloak-bearer.json](keycloak-bearer.json) into WildFly. File `keycloak-bearer.json` is currently used for adapters on server (JAAS Login module) side. File `keycloak-hawtio.json` is used on client (Hawtio JS application) side.
+
+ cp examples/keycloak-integration/keycloak-hawtio.json $JBOSS_HOME/standalone/configuration/
+ cp examples/keycloak-integration/keycloak-bearer.json $JBOSS_HOME/standalone/configuration/
+
+* In `$JBOSS_HOME/standalone/configuration/standalone.xml` configure system properties like this:
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+
+
+ Also add `hawtio` realm to this file in `` section:
+
+
+
+
+
+
+
+
+
+* Add the `` section to the `keycloak` subsystem in `$JBOSS_HOME/standalone/configuration/standalone.xml`. It should ensure that Hawtio WAR is able to find the JAAS login modules.
+
+
+
+ does-not-matter
+ does-not-matter
+
+
+
+* Run WildFly on port `8080` and go to http://localhost:8080/hawtio. Users are again `admin` and `viewer` with access and `jdoe` without access.
+
+
+## Jetty
+
+Assume `$JETTY_HOME` is the root directory of your Jetty installation and you deployed Hawtio WAR to Jetty as described in [hawtio Get Started](http://hawt.io/getstarted/index.html).
+
+* Install Keycloak Jetty adapter into your Jetty server as described on: http://www.keycloak.org/docs/3.4/securing_apps/index.html#_jetty9_adapter
+
+* Download and copy [keycloak-hawtio.json](keycloak-hawtio.json) and [keycloak-bearer.json](keycloak-bearer.json) into Jetty. File `keycloak-bearer.json` is currently used for adapters on server (JAAS Login module) side. File `keycloak-hawtio.json` is used on client (Hawtio JS application) side.
+
+ cp examples/keycloak-integration/keycloak-hawtio.json $JETTY_HOME/etc/
+ cp examples/keycloak-integration/keycloak-bearer.json $JETTY_HOME/etc/
+
+* Create file `$JETTY_HOME/etc/login.conf` with the content like this:
+
+ hawtio {
+ org.keycloak.adapters.jaas.BearerTokenLoginModule required
+ keycloak-config-file="${hawtio.keycloakServerConfig}";
+ };
+
+* Export `JETTY_HOME` in your terminal. For example:
+
+ export JETTY_HOME=/mydir/jetty-distribution-9.x.x
+
+* Export `JAVA_OPTIONS` and add all necessary system properties similarly like this:
+
+ export JAVA_OPTIONS="-Dhawtio.authenticationEnabled=true \
+ -Dhawtio.realm=hawtio \
+ -Dhawtio.keycloakEnabled=true \
+ -Dhawtio.roles=admin,manager,viewer \
+ -Dhawtio.rolePrincipalClasses=org.keycloak.adapters.jaas.RolePrincipal \
+ -Dhawtio.keycloakClientConfig=$JETTY_HOME/etc/keycloak-hawtio.json \
+ -Dhawtio.keycloakServerConfig=$JETTY_HOME/etc/keycloak-bearer.json \
+ -Djava.security.auth.login.config=$JETTY_HOME/etc/login.conf"
+
+* Run Jetty and go to http://localhost:8080/hawtio. Users are again `admin` and `viewer` with access and `jdoe` without access.
+
+
+## Tomcat
+
+Instructions are quite similar to Jetty. You would need to setup JAAS realm and set the system properties. Just use Tomcat adapter instead of the Jetty one. Also you may need to add this system property (really empty value):
+
+ -Dhawtio.authenticationContainerDiscoveryClasses=
+
+This is needed, so that Tomcat will use configured JAAS realm with `BearerTokenLoginModule` instead of `tomcat-users.xml` file, which Hawtio uses on Tomcat by default.
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-bearer.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-bearer.json"
new file mode 100755
index 0000000..c488a52
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-bearer.json"
@@ -0,0 +1,9 @@
+{
+ "realm": "hawtio-demo",
+ "resource": "jaas",
+ "bearer-only": true,
+ "auth-server-url": "http://localhost:18080/auth",
+ "ssl-required": "external",
+ "use-resource-role-mappings": false,
+ "principal-attribute": "preferred_username"
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-direct-access.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-direct-access.json"
new file mode 100755
index 0000000..07e2b0f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-direct-access.json"
@@ -0,0 +1,9 @@
+{
+ "realm": "hawtio-demo",
+ "resource": "ssh-jmx-admin-client",
+ "ssl-required": "external",
+ "auth-server-url": "http://localhost:18080/auth",
+ "credentials": {
+ "secret": "password"
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-hawtio.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-hawtio.json"
new file mode 100755
index 0000000..24b0ac6
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/keycloak-hawtio.json"
@@ -0,0 +1,5 @@
+{
+ "url": "http://localhost:18080/auth",
+ "realm": "hawtio-demo",
+ "clientId": "hawtio-client"
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/login.conf" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/login.conf"
new file mode 100755
index 0000000..3a20549
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/login.conf"
@@ -0,0 +1,4 @@
+hawtio {
+ org.keycloak.adapters.jaas.BearerTokenLoginModule required
+ keycloak-config-file="${hawtio.keycloakServerConfig}";
+};
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/run-hawtio.sh" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/run-hawtio.sh"
new file mode 100755
index 0000000..76845ac
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/keycloak-integration/run-hawtio.sh"
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+if [ -z $1 ]; then
+ echo "Usage:"
+ echo " ./run-hawtio.sh "
+ exit 1
+fi
+
+HOME=`cd $(dirname $0); pwd`
+
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.authenticationEnabled=true"
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.realm=hawtio"
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.keycloakEnabled=true"
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.roles=admin,manager,viewer"
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.rolePrincipalClasses=org.keycloak.adapters.jaas.RolePrincipal"
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.keycloakClientConfig=$HOME/keycloak-hawtio.json"
+JAVA_OPTS="$JAVA_OPTS -Dhawtio.keycloakServerConfig=$HOME/keycloak-bearer.json"
+JAVA_OPTS="$JAVA_OPTS -Djava.security.auth.login.config=$HOME/login.conf"
+
+echo =========================================================================
+echo
+echo " hawtio integration with Keycloak"
+echo
+echo " java $JAVA_OPTS -jar $*"
+echo
+echo =========================================================================
+java $JAVA_OPTS -jar $*
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/README.md"
new file mode 100755
index 0000000..1afb4dc
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/README.md"
@@ -0,0 +1,11 @@
+# Hawtio Spring boot 1 Authentication Example
+
+Sample application for Hawtio + Spring Boot 1 with authentication enabled.
+
+Run with
+
+ mvn spring-boot:run
+
+Browse Hawtio using the url: http://localhost:10001/hawtio/index.html
+
+Log in with user: `hawtio` password: `hawtio`
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/pom.xml"
new file mode 100755
index 0000000..3400b7e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/pom.xml"
@@ -0,0 +1,103 @@
+
+
+
+ 4.0.0
+
+
+ io.hawt
+ project
+ 2.5.0
+ ../..
+
+
+ io.hawt.examples
+ hawtio-example-springboot-1-authentication
+ ${project.artifactId}
+ hawtio :: Sample Spring Boot 1.x process with authentication
+ war
+
+
+
+ 9.4.9.v20180320
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot1-version}
+ pom
+ import
+
+
+ io.hawt
+ hawtio-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+ org.eclipse.jetty
+ jetty-jaas
+ ${jetty.version}
+
+
+ org.eclipse.jetty
+ jetty-http
+
+
+ org.springframework.boot
+ spring-boot-actuator
+
+
+ io.hawt
+ hawtio-springboot-1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot1-version}
+
+ io.hawt.example.spring.boot.SampleAuthenticationSpringBootService
+
+
+
+
+ repackage
+
+
+
+
+
+ maven-war-plugin
+
+ false
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/HelloController.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/HelloController.java"
new file mode 100755
index 0000000..3c6b7a8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/HelloController.java"
@@ -0,0 +1,16 @@
+package io.hawt.example.spring.boot;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class HelloController {
+
+ @RequestMapping("/")
+ @ResponseBody
+ public String hello() {
+ return "Hello World!";
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/PropertyFileLoginModule.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/PropertyFileLoginModule.java"
new file mode 100755
index 0000000..5fcb1ee
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/PropertyFileLoginModule.java"
@@ -0,0 +1,108 @@
+package io.hawt.example.spring.boot;
+
+import org.eclipse.jetty.jaas.spi.AbstractLoginModule;
+import org.eclipse.jetty.jaas.spi.UserInfo;
+import org.eclipse.jetty.security.PropertyUserStore;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.security.Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Sample PropertyFileLoginModule.
+ */
+public class PropertyFileLoginModule extends AbstractLoginModule {
+ public static final String DEFAULT_FILENAME = "realm.properties";
+
+ private static final Logger LOG = LoggerFactory.getLogger(PropertyFileLoginModule.class);
+ private static ConcurrentHashMap PROPERTY_USERSTORES = new ConcurrentHashMap<>();
+
+ private boolean hotReload = false;
+ private String filename = null;
+
+ /**
+ * Read contents of the configured property file.
+ *
+ * @param subject
+ * @param callbackHandler
+ * @param sharedState
+ * @param options
+ * @see javax.security.auth.spi.LoginModule#initialize(Subject, CallbackHandler, Map, Map)
+ */
+ @Override
+ public void initialize(final Subject subject, final CallbackHandler callbackHandler,
+ final Map sharedState, final Map options) {
+ super.initialize(subject, callbackHandler, sharedState, options);
+ setupPropertyUserStore(options);
+ }
+
+ private void setupPropertyUserStore(final Map options) {
+ parseConfig(options);
+
+ if (PROPERTY_USERSTORES.get(filename) == null) {
+ final PropertyUserStore propertyUserStore = new PropertyUserStore();
+ propertyUserStore.setConfig(filename);
+ propertyUserStore.setHotReload(hotReload);
+
+ final PropertyUserStore prev = PROPERTY_USERSTORES.putIfAbsent(filename, propertyUserStore);
+ if (prev == null) {
+ LOG.info("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + filename
+ + " hotReload: " + hotReload);
+
+ try {
+ propertyUserStore.start();
+ } catch (Exception e) {
+ LOG.warn("Exception while starting propertyUserStore: ", e);
+ }
+ }
+ }
+ }
+
+ private void parseConfig(final Map options) {
+ String tmp = (String) options.get("file");
+ filename = (tmp == null ? DEFAULT_FILENAME : tmp);
+ filename = System.getProperty("login.file", filename);
+ tmp = (String) options.get("hotReload");
+ hotReload = tmp == null ? hotReload : Boolean.parseBoolean(tmp);
+ }
+
+ @Override
+ public UserInfo getUserInfo(final String userName) {
+ final PropertyUserStore propertyUserStore = PROPERTY_USERSTORES.get(filename);
+ if (propertyUserStore == null) {
+ throw new IllegalStateException("PropertyUserStore should never be null here!");
+ }
+
+ LOG.trace("Checking PropertyUserStore " + filename + " for " + userName);
+ final UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName);
+ if (userIdentity == null) {
+ return null;
+ }
+
+ final Set principals = userIdentity.getSubject().getPrincipals();
+ final List roles = new ArrayList<>();
+ for (final Principal principal : principals) {
+ roles.add(principal.getName());
+ }
+
+ final Credential credential = (Credential) userIdentity.getSubject().getPrivateCredentials().iterator().next();
+ LOG.trace("Found: " + userName + " in PropertyUserStore " + filename);
+ return new UserInfo(userName, credential, roles);
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ return true;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/SampleAuthenticationSpringBootService.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/SampleAuthenticationSpringBootService.java"
new file mode 100755
index 0000000..2a795ee
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/java/io/hawt/example/spring/boot/SampleAuthenticationSpringBootService.java"
@@ -0,0 +1,71 @@
+package io.hawt.example.spring.boot;
+
+import java.net.URL;
+
+import io.hawt.config.ConfigFacade;
+import io.hawt.springboot.HawtPlugin;
+import io.hawt.web.auth.AuthenticationConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class SampleAuthenticationSpringBootService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SampleAuthenticationSpringBootService.class);
+ private static final String JAVA_SECURITY_AUTH_LOGIN_CONFIG = "java.security.auth.login.config";
+
+
+ public static void main(String[] args) {
+ System.setProperty(AuthenticationConfiguration.HAWTIO_AUTHENTICATION_ENABLED, "false");
+ SpringApplication.run(SampleAuthenticationSpringBootService.class, args);
+ }
+
+ /**
+ * Loading an example plugin.
+ */
+ @Bean
+ public HawtPlugin samplePlugin() {
+ return new HawtPlugin("sample-plugin", "plugins", "", new String[] { "sample-plugin/js/sample-plugin.js" });
+ }
+
+ /**
+ * Configure facade to use authentication.
+ *
+ * @return config
+ * @throws Exception if an error occurs
+ */
+ @Bean(initMethod = "init")
+ public ConfigFacade configFacade() throws Exception {
+
+ final URL loginResource = this.getClass().getClassLoader().getResource("login.conf");
+ if (loginResource != null) {
+ setSystemPropertyIfNotSet(JAVA_SECURITY_AUTH_LOGIN_CONFIG, loginResource.getFile());
+ }
+ LOG.info("Using loginResource " + JAVA_SECURITY_AUTH_LOGIN_CONFIG + " : " + System
+ .getProperty(JAVA_SECURITY_AUTH_LOGIN_CONFIG));
+
+ final URL loginFile = this.getClass().getClassLoader().getResource("realm.properties");
+ if (loginFile != null) {
+ setSystemPropertyIfNotSet("login.file", loginFile.getFile());
+ }
+ LOG.info("Using login.file : " + System.getProperty("login.file"));
+
+ setSystemPropertyIfNotSet(AuthenticationConfiguration.HAWTIO_ROLES, "admin");
+ setSystemPropertyIfNotSet(AuthenticationConfiguration.HAWTIO_REALM, "hawtio");
+ setSystemPropertyIfNotSet(AuthenticationConfiguration.HAWTIO_ROLE_PRINCIPAL_CLASSES, "org.eclipse.jetty.jaas.JAASRole");
+ if (!Boolean.getBoolean("debugMode")) {
+ System.setProperty(AuthenticationConfiguration.HAWTIO_AUTHENTICATION_ENABLED, "true");
+ }
+ return new ConfigFacade();
+ }
+
+ private void setSystemPropertyIfNotSet(final String key, final String value) {
+ if (System.getProperty(key) == null) {
+ System.setProperty(key, value);
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/application.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/application.properties"
new file mode 100755
index 0000000..4379ceb
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/application.properties"
@@ -0,0 +1,10 @@
+server.port = 10000
+management.port = 10001
+
+endpoints.jolokia.sensitive = false
+endpoints.hawtio.sensitive = false
+
+logging.level.io.hawt = INFO
+logging.level.org.springframework = WARN
+logging.level.io.undertow = WARN
+logging.level.org.eclipse.jetty = WARN
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/banner.txt" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/banner.txt"
new file mode 100755
index 0000000..e832f57
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/banner.txt"
@@ -0,0 +1,9 @@
+ _______________________________
+/ Hawtio SpringBoot Sample With \
+\ Authentication /
+ -------------------------------
+ \ ^__^
+ \ (oo)\_______
+ (__)\ )\/\
+ ||----w |
+ || ||
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/jolokia-access.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/jolokia-access.xml"
new file mode 100755
index 0000000..d714f34
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/jolokia-access.xml"
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ read
+ write
+ exec
+ list
+ version
+ search
+
+
+
+
+
+
+
+
+
+ com.mchange.v2.c3p0:type=PooledDataSource,*
+ properties
+
+
+
+
+
+
+ *
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/login.conf" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/login.conf"
new file mode 100755
index 0000000..6c4cfc1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/login.conf"
@@ -0,0 +1,3 @@
+hawtio {
+ io.hawt.example.spring.boot.PropertyFileLoginModule required;
+};
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/realm.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/realm.properties"
new file mode 100755
index 0000000..77055d3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/resources/realm.properties"
@@ -0,0 +1,7 @@
+#
+# Hash generated with:
+# java -cp ~/.m2/repository/org/eclipse/jetty/jetty-util/9.2.11.v20150529/jetty-util-9.2.11.v20150529.jar org.eclipse.jetty.util.security.Password hawtio hawtio
+#
+
+hawtio: MD5:2d3c8a35f1d0c2a1a6ff1dc4ba221476,user,admin
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/webapp/app/sample-plugin/html/sample-plugin.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
new file mode 100755
index 0000000..d76f916
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
@@ -0,0 +1,8 @@
+
+
+
+
Demo Page
+
{{message}}
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/webapp/app/sample-plugin/js/sample-plugin.js" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
new file mode 100755
index 0000000..928c6f0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1-authentication/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
@@ -0,0 +1,41 @@
+var SamplePlugin = (function(SamplePlugin) {
+
+ SamplePlugin.pluginName = 'sample-plugin';
+ SamplePlugin.log = Logger.get('SamplePlugin');
+ SamplePlugin.contextPath = window.location.pathname.substr(0, window.location.pathname.lastIndexOf("/")) + "/plugins/";
+ SamplePlugin.templatePath = SamplePlugin.contextPath + "sample-plugin/html/";
+
+ SamplePlugin.module = angular.module('sample-plugin', ['hawtioCore'])
+ .config(function($routeProvider) {
+ $routeProvider.
+ when('/sample-plugin', {
+ templateUrl: SamplePlugin.templatePath + 'sample-plugin.html'
+ });
+ });
+
+ SamplePlugin.module.run(function(workspace, viewRegistry, layoutFull) {
+
+ SamplePlugin.log.info(SamplePlugin.pluginName, " loaded");
+ viewRegistry["sample-plugin"] = layoutFull;
+ workspace.topLevelTabs.push({
+ id: "samplePlugin",
+ content: "Sample Plugin",
+ title: "Sample plugin loaded dynamically",
+ isValid: function(workspace) { return true; },
+ href: function() { return "#/sample-plugin"; },
+ isActive: function(workspace) { return workspace.isLinkActive("sample-plugin"); }
+
+ });
+
+ });
+
+ SamplePlugin.SamplePluginController = function($scope, jolokia) {
+ $scope.message = "hello world";
+ Core.$apply($scope);
+ };
+
+ return SamplePlugin;
+
+})(SamplePlugin || {});
+
+hawtioPluginLoader.addModule(SamplePlugin.pluginName);
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/README.md"
new file mode 100755
index 0000000..1da3fdb
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/README.md"
@@ -0,0 +1,32 @@
+# Hawtio Spring Boot 1 Example
+
+This sample application shows how to run Hawtio with Spring Boot 1.
+
+## How to run
+
+Run with:
+
+ mvn spring-boot:run
+
+Hawtio is exposed at the [Actuator](https://docs.spring.io/spring-boot/docs/1.5.x/reference/html/production-ready-endpoints.html) management port configured using
+`management.port` in `appplication.properties`. Browse Hawtio via the following URL: http://localhost:10001/hawtio/index.html
+
+The actual application is running on port 10000 (`server.port` in `application.properties`).
+
+## Alternative configurations
+
+Alternative ports and context path configurations can be tested by changing the following properties in `application.properties`:
+
+```
+server.port = 10000
+server.contextPath = /sample-app
+management.port = 10000
+management.contextPath = /management
+```
+
+Using the above configuration, the server will use port 10000 and the custom context path `sample-app`.
+The Actuator management endpoints and Hawtio will also run on port 10000 using the custom management context path `management`.
+The URLs for accessing the application and Hawtio are as follows:
+
+- Application: http://localhost:10000/sample-app/
+- Hawtio: http://localhost:10000/sample-app/management/hawtio
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/pom.xml"
new file mode 100755
index 0000000..4fe7452
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/pom.xml"
@@ -0,0 +1,127 @@
+
+
+
+ 4.0.0
+
+
+ io.hawt
+ project
+ 2.5.0
+ ../..
+
+
+ io.hawt.examples
+ hawtio-example-springboot-1
+ ${project.artifactId}
+ hawtio :: Sample Spring Boot 1.x process
+ war
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot1-version}
+ pom
+ import
+
+
+ org.apache.camel
+ camel-spring-boot-dependencies
+ ${camel-2.21-version}
+ pom
+ import
+
+
+ io.hawt
+ hawtio-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+ io.undertow
+ undertow-websockets-jsr
+
+
+
+
+ org.springframework.boot
+ spring-boot-actuator
+
+
+
+
+ io.hawt
+ hawtio-springboot-1
+
+
+
+
+ org.apache.camel
+ camel-spring-boot-starter
+
+
+ org.apache.camel
+ camel-stream-starter
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot1-version}
+
+ io.hawt.example.spring.boot.SampleSpringBootService
+
+
+
+
+ repackage
+
+
+
+
+
+
+ maven-war-plugin
+
+ false
+
+
+
+
+
+ io.hawt
+ hawtio-maven-plugin
+ ${project.version}
+
+ io.hawt.example.spring.boot.SampleSpringBootService
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/HelloController.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/HelloController.java"
new file mode 100755
index 0000000..3c6b7a8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/HelloController.java"
@@ -0,0 +1,16 @@
+package io.hawt.example.spring.boot;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class HelloController {
+
+ @RequestMapping("/")
+ @ResponseBody
+ public String hello() {
+ return "Hello World!";
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/SampleCamelRouter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/SampleCamelRouter.java"
new file mode 100755
index 0000000..afe8d31
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/SampleCamelRouter.java"
@@ -0,0 +1,17 @@
+package io.hawt.example.spring.boot;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SampleCamelRouter extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ from("timer:hello?period={{timer.period}}")
+ .setBody().constant("Hello Camel!")
+ .to("stream:out")
+ .to("mock:result");
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/SampleSpringBootService.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/SampleSpringBootService.java"
new file mode 100755
index 0000000..0a74cba
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/java/io/hawt/example/spring/boot/SampleSpringBootService.java"
@@ -0,0 +1,41 @@
+package io.hawt.example.spring.boot;
+
+import io.hawt.config.ConfigFacade;
+import io.hawt.springboot.HawtPlugin;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class SampleSpringBootService extends SpringBootServletInitializer {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SampleSpringBootService.class, args);
+ }
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(SampleSpringBootService.class);
+ }
+
+ /**
+ * Loading an example plugin.
+ */
+ @Bean
+ public HawtPlugin samplePlugin() {
+ return new HawtPlugin("sample-plugin",
+ "plugins",
+ "",
+ new String[] { "sample-plugin/js/sample-plugin.js" });
+ }
+
+ /**
+ * Set things up to be in offline mode.
+ */
+ @Bean
+ public ConfigFacade configFacade() {
+ return ConfigFacade.getSingleton();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/resources/application.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/resources/application.properties"
new file mode 100755
index 0000000..5af461b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/resources/application.properties"
@@ -0,0 +1,15 @@
+server.port = 10000
+management.port = 10001
+
+endpoints.jolokia.sensitive = false
+endpoints.hawtio.sensitive = false
+
+logging.level.io.hawt = INFO
+logging.level.org.springframework = WARN
+logging.level.io.undertow = WARN
+
+camel.springboot.name = SampleCamel
+timer.period = 10000
+
+hawtio.authenticationEnabled = false
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/resources/banner.txt" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/resources/banner.txt"
new file mode 100755
index 0000000..3770eff
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/resources/banner.txt"
@@ -0,0 +1,8 @@
+ __________________________
+< Hawtio SpringBoot Sample >
+ --------------------------
+ \ ^__^
+ \ (oo)\_______
+ (__)\ )\/\
+ ||----w |
+ || ||
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/webapp/app/sample-plugin/html/sample-plugin.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
new file mode 100755
index 0000000..d76f916
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
@@ -0,0 +1,8 @@
+
+
+
+
Demo Page
+
{{message}}
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/webapp/app/sample-plugin/js/sample-plugin.js" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
new file mode 100755
index 0000000..2b425eb
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-1/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
@@ -0,0 +1,41 @@
+var SamplePlugin = (function(SamplePlugin) {
+
+ SamplePlugin.pluginName = 'sample-plugin';
+ SamplePlugin.log = Logger.get('SamplePlugin');
+ SamplePlugin.contextPath = window.location.pathname.substr(0, window.location.pathname.lastIndexOf("/")) + "/plugins/";
+ SamplePlugin.templatePath = SamplePlugin.contextPath + "sample-plugin/html/";
+
+ SamplePlugin.module = angular.module('sample-plugin', ['hawtioCore'])
+ .config(function($routeProvider) {
+ $routeProvider.
+ when('/sample-plugin', {
+ templateUrl: SamplePlugin.templatePath + 'sample-plugin.html'
+ });
+ });
+
+ SamplePlugin.module.run(function(workspace, viewRegistry, layoutFull) {
+
+ SamplePlugin.log.info(SamplePlugin.pluginName, " loaded");
+ viewRegistry["sample-plugin"] = layoutFull;
+ workspace.topLevelTabs.push({
+ id: "samplePlugin",
+ content: "Sample Plugin",
+ title: "Sample plugin loaded dynamically",
+ isValid: function(workspace) { return true; },
+ href: function() { return "#/sample-plugin"; },
+ isActive: function(workspace) { return workspace.isLinkActive("sample-plugin"); }
+
+ });
+
+ });
+
+ SamplePlugin.SamplePluginController = function($scope, jolokia) {
+ $scope.message = "hello world";
+ Core.$apply($scope);
+ };
+
+ return SamplePlugin;
+
+})(SamplePlugin || {});
+
+hawtioPluginLoader.addModule(SamplePlugin.pluginName);
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/README.md"
new file mode 100755
index 0000000..c7e17b2
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/README.md"
@@ -0,0 +1,11 @@
+# Hawtio Spring boot 2 Authentication Example
+
+Sample application for Hawtio + Spring Boot 2 with authentication enabled.
+
+Run with
+
+ mvn spring-boot:run
+
+Browse Hawtio using the url: http://localhost:10001/actuator/hawtio/index.html
+
+Log in with user: `hawtio` password: `hawtio`
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/pom.xml"
new file mode 100755
index 0000000..7d67b74
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/pom.xml"
@@ -0,0 +1,103 @@
+
+
+
+ 4.0.0
+
+
+ io.hawt
+ project
+ 2.5.0
+ ../..
+
+
+ io.hawt.examples
+ hawtio-example-springboot-authentication
+ ${project.artifactId}
+ hawtio :: Sample Spring Boot 2.x process with authentication
+ war
+
+
+
+ 9.4.11.v20180605
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot-version}
+ pom
+ import
+
+
+ io.hawt
+ hawtio-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+ org.eclipse.jetty
+ jetty-jaas
+ ${jetty.version}
+
+
+ org.eclipse.jetty
+ jetty-http
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ io.hawt
+ hawtio-springboot
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot-version}
+
+ io.hawt.example.spring.boot.SampleAuthenticationSpringBootService
+
+
+
+
+ repackage
+
+
+
+
+
+ maven-war-plugin
+
+ false
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/HelloController.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/HelloController.java"
new file mode 100755
index 0000000..3c6b7a8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/HelloController.java"
@@ -0,0 +1,16 @@
+package io.hawt.example.spring.boot;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class HelloController {
+
+ @RequestMapping("/")
+ @ResponseBody
+ public String hello() {
+ return "Hello World!";
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/PropertyFileLoginModule.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/PropertyFileLoginModule.java"
new file mode 100755
index 0000000..5fcb1ee
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/PropertyFileLoginModule.java"
@@ -0,0 +1,108 @@
+package io.hawt.example.spring.boot;
+
+import org.eclipse.jetty.jaas.spi.AbstractLoginModule;
+import org.eclipse.jetty.jaas.spi.UserInfo;
+import org.eclipse.jetty.security.PropertyUserStore;
+import org.eclipse.jetty.server.UserIdentity;
+import org.eclipse.jetty.util.security.Credential;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Sample PropertyFileLoginModule.
+ */
+public class PropertyFileLoginModule extends AbstractLoginModule {
+ public static final String DEFAULT_FILENAME = "realm.properties";
+
+ private static final Logger LOG = LoggerFactory.getLogger(PropertyFileLoginModule.class);
+ private static ConcurrentHashMap PROPERTY_USERSTORES = new ConcurrentHashMap<>();
+
+ private boolean hotReload = false;
+ private String filename = null;
+
+ /**
+ * Read contents of the configured property file.
+ *
+ * @param subject
+ * @param callbackHandler
+ * @param sharedState
+ * @param options
+ * @see javax.security.auth.spi.LoginModule#initialize(Subject, CallbackHandler, Map, Map)
+ */
+ @Override
+ public void initialize(final Subject subject, final CallbackHandler callbackHandler,
+ final Map sharedState, final Map options) {
+ super.initialize(subject, callbackHandler, sharedState, options);
+ setupPropertyUserStore(options);
+ }
+
+ private void setupPropertyUserStore(final Map options) {
+ parseConfig(options);
+
+ if (PROPERTY_USERSTORES.get(filename) == null) {
+ final PropertyUserStore propertyUserStore = new PropertyUserStore();
+ propertyUserStore.setConfig(filename);
+ propertyUserStore.setHotReload(hotReload);
+
+ final PropertyUserStore prev = PROPERTY_USERSTORES.putIfAbsent(filename, propertyUserStore);
+ if (prev == null) {
+ LOG.info("setupPropertyUserStore: Starting new PropertyUserStore. PropertiesFile: " + filename
+ + " hotReload: " + hotReload);
+
+ try {
+ propertyUserStore.start();
+ } catch (Exception e) {
+ LOG.warn("Exception while starting propertyUserStore: ", e);
+ }
+ }
+ }
+ }
+
+ private void parseConfig(final Map options) {
+ String tmp = (String) options.get("file");
+ filename = (tmp == null ? DEFAULT_FILENAME : tmp);
+ filename = System.getProperty("login.file", filename);
+ tmp = (String) options.get("hotReload");
+ hotReload = tmp == null ? hotReload : Boolean.parseBoolean(tmp);
+ }
+
+ @Override
+ public UserInfo getUserInfo(final String userName) {
+ final PropertyUserStore propertyUserStore = PROPERTY_USERSTORES.get(filename);
+ if (propertyUserStore == null) {
+ throw new IllegalStateException("PropertyUserStore should never be null here!");
+ }
+
+ LOG.trace("Checking PropertyUserStore " + filename + " for " + userName);
+ final UserIdentity userIdentity = propertyUserStore.getUserIdentity(userName);
+ if (userIdentity == null) {
+ return null;
+ }
+
+ final Set principals = userIdentity.getSubject().getPrincipals();
+ final List roles = new ArrayList<>();
+ for (final Principal principal : principals) {
+ roles.add(principal.getName());
+ }
+
+ final Credential credential = (Credential) userIdentity.getSubject().getPrivateCredentials().iterator().next();
+ LOG.trace("Found: " + userName + " in PropertyUserStore " + filename);
+ return new UserInfo(userName, credential, roles);
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ return true;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/SampleAuthenticationSpringBootService.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/SampleAuthenticationSpringBootService.java"
new file mode 100755
index 0000000..2a795ee
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/java/io/hawt/example/spring/boot/SampleAuthenticationSpringBootService.java"
@@ -0,0 +1,71 @@
+package io.hawt.example.spring.boot;
+
+import java.net.URL;
+
+import io.hawt.config.ConfigFacade;
+import io.hawt.springboot.HawtPlugin;
+import io.hawt.web.auth.AuthenticationConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class SampleAuthenticationSpringBootService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SampleAuthenticationSpringBootService.class);
+ private static final String JAVA_SECURITY_AUTH_LOGIN_CONFIG = "java.security.auth.login.config";
+
+
+ public static void main(String[] args) {
+ System.setProperty(AuthenticationConfiguration.HAWTIO_AUTHENTICATION_ENABLED, "false");
+ SpringApplication.run(SampleAuthenticationSpringBootService.class, args);
+ }
+
+ /**
+ * Loading an example plugin.
+ */
+ @Bean
+ public HawtPlugin samplePlugin() {
+ return new HawtPlugin("sample-plugin", "plugins", "", new String[] { "sample-plugin/js/sample-plugin.js" });
+ }
+
+ /**
+ * Configure facade to use authentication.
+ *
+ * @return config
+ * @throws Exception if an error occurs
+ */
+ @Bean(initMethod = "init")
+ public ConfigFacade configFacade() throws Exception {
+
+ final URL loginResource = this.getClass().getClassLoader().getResource("login.conf");
+ if (loginResource != null) {
+ setSystemPropertyIfNotSet(JAVA_SECURITY_AUTH_LOGIN_CONFIG, loginResource.getFile());
+ }
+ LOG.info("Using loginResource " + JAVA_SECURITY_AUTH_LOGIN_CONFIG + " : " + System
+ .getProperty(JAVA_SECURITY_AUTH_LOGIN_CONFIG));
+
+ final URL loginFile = this.getClass().getClassLoader().getResource("realm.properties");
+ if (loginFile != null) {
+ setSystemPropertyIfNotSet("login.file", loginFile.getFile());
+ }
+ LOG.info("Using login.file : " + System.getProperty("login.file"));
+
+ setSystemPropertyIfNotSet(AuthenticationConfiguration.HAWTIO_ROLES, "admin");
+ setSystemPropertyIfNotSet(AuthenticationConfiguration.HAWTIO_REALM, "hawtio");
+ setSystemPropertyIfNotSet(AuthenticationConfiguration.HAWTIO_ROLE_PRINCIPAL_CLASSES, "org.eclipse.jetty.jaas.JAASRole");
+ if (!Boolean.getBoolean("debugMode")) {
+ System.setProperty(AuthenticationConfiguration.HAWTIO_AUTHENTICATION_ENABLED, "true");
+ }
+ return new ConfigFacade();
+ }
+
+ private void setSystemPropertyIfNotSet(final String key, final String value) {
+ if (System.getProperty(key) == null) {
+ System.setProperty(key, value);
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/application.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/application.properties"
new file mode 100755
index 0000000..de623ce
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/application.properties"
@@ -0,0 +1,9 @@
+server.port=10000
+management.server.port=10001
+
+management.endpoints.web.exposure.include=hawtio,jolokia
+
+logging.level.io.hawt=INFO
+logging.level.org.springframework=WARN
+logging.level.io.undertow=WARN
+logging.level.org.eclipse.jetty=WARN
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/banner.txt" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/banner.txt"
new file mode 100755
index 0000000..e832f57
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/banner.txt"
@@ -0,0 +1,9 @@
+ _______________________________
+/ Hawtio SpringBoot Sample With \
+\ Authentication /
+ -------------------------------
+ \ ^__^
+ \ (oo)\_______
+ (__)\ )\/\
+ ||----w |
+ || ||
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/jolokia-access.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/jolokia-access.xml"
new file mode 100755
index 0000000..d714f34
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/jolokia-access.xml"
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ read
+ write
+ exec
+ list
+ version
+ search
+
+
+
+
+
+
+
+
+
+ com.mchange.v2.c3p0:type=PooledDataSource,*
+ properties
+
+
+
+
+
+
+ *
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/login.conf" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/login.conf"
new file mode 100755
index 0000000..6c4cfc1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/login.conf"
@@ -0,0 +1,3 @@
+hawtio {
+ io.hawt.example.spring.boot.PropertyFileLoginModule required;
+};
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/realm.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/realm.properties"
new file mode 100755
index 0000000..77055d3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/resources/realm.properties"
@@ -0,0 +1,7 @@
+#
+# Hash generated with:
+# java -cp ~/.m2/repository/org/eclipse/jetty/jetty-util/9.2.11.v20150529/jetty-util-9.2.11.v20150529.jar org.eclipse.jetty.util.security.Password hawtio hawtio
+#
+
+hawtio: MD5:2d3c8a35f1d0c2a1a6ff1dc4ba221476,user,admin
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/webapp/app/sample-plugin/html/sample-plugin.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
new file mode 100755
index 0000000..d76f916
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
@@ -0,0 +1,8 @@
+
+
+
+
Demo Page
+
{{message}}
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/webapp/app/sample-plugin/js/sample-plugin.js" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
new file mode 100755
index 0000000..928c6f0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot-authentication/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
@@ -0,0 +1,41 @@
+var SamplePlugin = (function(SamplePlugin) {
+
+ SamplePlugin.pluginName = 'sample-plugin';
+ SamplePlugin.log = Logger.get('SamplePlugin');
+ SamplePlugin.contextPath = window.location.pathname.substr(0, window.location.pathname.lastIndexOf("/")) + "/plugins/";
+ SamplePlugin.templatePath = SamplePlugin.contextPath + "sample-plugin/html/";
+
+ SamplePlugin.module = angular.module('sample-plugin', ['hawtioCore'])
+ .config(function($routeProvider) {
+ $routeProvider.
+ when('/sample-plugin', {
+ templateUrl: SamplePlugin.templatePath + 'sample-plugin.html'
+ });
+ });
+
+ SamplePlugin.module.run(function(workspace, viewRegistry, layoutFull) {
+
+ SamplePlugin.log.info(SamplePlugin.pluginName, " loaded");
+ viewRegistry["sample-plugin"] = layoutFull;
+ workspace.topLevelTabs.push({
+ id: "samplePlugin",
+ content: "Sample Plugin",
+ title: "Sample plugin loaded dynamically",
+ isValid: function(workspace) { return true; },
+ href: function() { return "#/sample-plugin"; },
+ isActive: function(workspace) { return workspace.isLinkActive("sample-plugin"); }
+
+ });
+
+ });
+
+ SamplePlugin.SamplePluginController = function($scope, jolokia) {
+ $scope.message = "hello world";
+ Core.$apply($scope);
+ };
+
+ return SamplePlugin;
+
+})(SamplePlugin || {});
+
+hawtioPluginLoader.addModule(SamplePlugin.pluginName);
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/README.md"
new file mode 100755
index 0000000..d045f41
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/README.md"
@@ -0,0 +1,50 @@
+# Hawtio Spring Boot 2 Example
+
+This sample application shows how to run Hawtio with Spring Boot 2.
+
+## How to run
+
+Run with:
+
+ mvn spring-boot:run
+
+Hawtio is exposed at the [Actuator](https://docs.spring.io/spring-boot/docs/latest/reference/html/production-ready-endpoints.html) management port configured using
+`management.server.port` in `appplication.properties`. Browse Hawtio via the following URL: http://localhost:10001/actuator/hawtio/index.html
+
+The actual application is running on port 10000 (`server.port` in `application.properties`).
+
+## Alternative configurations
+
+### Alternative management endpoint base paths
+If your preference is to avoid running Hawtio under the `/actuator` path, you can set the `management.endpoints.web.base-path` property in `application.properties`:
+
+```
+management.endpoints.web.base-path=/
+```
+
+Hawtio will then be available at http://localhost:10001/hawtio/index.html.
+
+### Alternative hawtio endpoint paths
+
+You can also customize the endpoint path of the Hawtio actuator endpoint by setting the `management.endpoints.web.path-mapping.hawtio` property in `application.properties`:
+
+```
+management.endpoints.web.path-mapping.hawtio=hawtio/console
+```
+
+### Alternative ports & context paths
+Alternative ports and context path configurations can be tested by changing the following properties in `application.properties`:
+
+```
+server.port=10000
+server.servlet.context-path=/sample-app
+management.port=10000
+management.server.servlet.context-path=/management
+```
+
+Using the above configuration, the server will use port 10000 and the custom context path `sample-app`.
+The Actuator management endpoints and Hawtio will also run on port 10000 using the custom management context path `management`.
+The URLs for accessing the application and Hawtio are as follows:
+
+- Application: http://localhost:10000/sample-app/
+- Hawtio: http://localhost:10000/sample-app/management/actuator/hawtio
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/jmx-exporter.yml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/jmx-exporter.yml"
new file mode 100755
index 0000000..02df234
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/jmx-exporter.yml"
@@ -0,0 +1,6 @@
+startDelaySecs: 5
+ssl: false
+lowercaseOutputName: true
+lowercaseOutputLabelNames: true
+blacklistObjectNames: ["java.lang:*"]
+attrNameSnakeCase: true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/pom.xml"
new file mode 100755
index 0000000..6a453de
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/pom.xml"
@@ -0,0 +1,157 @@
+
+
+
+ 4.0.0
+
+
+ io.hawt
+ project
+ 2.5.0
+ ../..
+
+
+ io.hawt.examples
+ hawtio-example-springboot
+ ${project.artifactId}
+ hawtio :: Sample Spring Boot 2.x process
+ war
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot-version}
+ pom
+ import
+
+
+ org.apache.camel
+ camel-spring-boot-dependencies
+ ${camel-version}
+ pom
+ import
+
+
+ io.hawt
+ hawtio-bom
+ ${project.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-undertow
+
+
+ io.undertow
+ undertow-websockets-jsr
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ io.hawt
+ hawtio-springboot
+
+
+
+
+ org.apache.camel
+ camel-spring-boot-starter
+
+
+ org.apache.camel
+ camel-stream-starter
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot-version}
+
+ io.hawt.example.spring.boot.SampleSpringBootService
+
+ -javaagent:./target/dependency/jmx_prometheus_javaagent.jar=10002:./jmx-exporter.yml
+
+
+
+
+
+ repackage
+
+
+
+
+
+
+ maven-war-plugin
+
+ false
+
+
+
+
+
+ io.hawt
+ hawtio-maven-plugin
+ ${project.version}
+
+ io.hawt.example.spring.boot.SampleSpringBootService
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.1
+
+
+ copy
+ compile
+
+ copy
+
+
+
+
+
+
+ io.prometheus.jmx
+ jmx_prometheus_javaagent
+ 0.3.1
+ jar
+ jmx_prometheus_javaagent.jar
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/HelloController.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/HelloController.java"
new file mode 100755
index 0000000..3c6b7a8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/HelloController.java"
@@ -0,0 +1,16 @@
+package io.hawt.example.spring.boot;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class HelloController {
+
+ @RequestMapping("/")
+ @ResponseBody
+ public String hello() {
+ return "Hello World!";
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/SampleCamelRouter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/SampleCamelRouter.java"
new file mode 100755
index 0000000..afe8d31
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/SampleCamelRouter.java"
@@ -0,0 +1,17 @@
+package io.hawt.example.spring.boot;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SampleCamelRouter extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ from("timer:hello?period={{timer.period}}")
+ .setBody().constant("Hello Camel!")
+ .to("stream:out")
+ .to("mock:result");
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/SampleSpringBootService.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/SampleSpringBootService.java"
new file mode 100755
index 0000000..5c393f8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/java/io/hawt/example/spring/boot/SampleSpringBootService.java"
@@ -0,0 +1,34 @@
+package io.hawt.example.spring.boot;
+
+import io.hawt.config.ConfigFacade;
+import io.hawt.springboot.HawtPlugin;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+@SpringBootApplication
+public class SampleSpringBootService {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SampleSpringBootService.class, args);
+ }
+
+ /**
+ * Loading an example plugin.
+ */
+ @Bean
+ public HawtPlugin samplePlugin() {
+ return new HawtPlugin("sample-plugin",
+ "plugins",
+ "",
+ new String[] { "sample-plugin/js/sample-plugin.js" });
+ }
+
+ /**
+ * Set things up to be in offline mode.
+ */
+ @Bean
+ public ConfigFacade configFacade() {
+ return ConfigFacade.getSingleton();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/resources/application.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/resources/application.properties"
new file mode 100755
index 0000000..1be96ba
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/resources/application.properties"
@@ -0,0 +1,12 @@
+server.port=10000
+management.server.port=10001
+
+management.endpoints.web.exposure.include=hawtio,jolokia
+
+logging.level.io.hawt=INFO
+logging.level.org.springframework=WARN
+logging.level.io.undertow=WARN
+
+camel.springboot.name=SampleCamel
+timer.period=10000
+hawtio.authenticationEnabled=false
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/resources/banner.txt" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/resources/banner.txt"
new file mode 100755
index 0000000..3770eff
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/resources/banner.txt"
@@ -0,0 +1,8 @@
+ __________________________
+< Hawtio SpringBoot Sample >
+ --------------------------
+ \ ^__^
+ \ (oo)\_______
+ (__)\ )\/\
+ ||----w |
+ || ||
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/webapp/app/sample-plugin/html/sample-plugin.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
new file mode 100755
index 0000000..d76f916
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/webapp/app/sample-plugin/html/sample-plugin.html"
@@ -0,0 +1,8 @@
+
+
+
+
Demo Page
+
{{message}}
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/webapp/app/sample-plugin/js/sample-plugin.js" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
new file mode 100755
index 0000000..2b425eb
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/examples/springboot/src/main/webapp/app/sample-plugin/js/sample-plugin.js"
@@ -0,0 +1,41 @@
+var SamplePlugin = (function(SamplePlugin) {
+
+ SamplePlugin.pluginName = 'sample-plugin';
+ SamplePlugin.log = Logger.get('SamplePlugin');
+ SamplePlugin.contextPath = window.location.pathname.substr(0, window.location.pathname.lastIndexOf("/")) + "/plugins/";
+ SamplePlugin.templatePath = SamplePlugin.contextPath + "sample-plugin/html/";
+
+ SamplePlugin.module = angular.module('sample-plugin', ['hawtioCore'])
+ .config(function($routeProvider) {
+ $routeProvider.
+ when('/sample-plugin', {
+ templateUrl: SamplePlugin.templatePath + 'sample-plugin.html'
+ });
+ });
+
+ SamplePlugin.module.run(function(workspace, viewRegistry, layoutFull) {
+
+ SamplePlugin.log.info(SamplePlugin.pluginName, " loaded");
+ viewRegistry["sample-plugin"] = layoutFull;
+ workspace.topLevelTabs.push({
+ id: "samplePlugin",
+ content: "Sample Plugin",
+ title: "Sample plugin loaded dynamically",
+ isValid: function(workspace) { return true; },
+ href: function() { return "#/sample-plugin"; },
+ isActive: function(workspace) { return workspace.isLinkActive("sample-plugin"); }
+
+ });
+
+ });
+
+ SamplePlugin.SamplePluginController = function($scope, jolokia) {
+ $scope.message = "hello world";
+ Core.$apply($scope);
+ };
+
+ return SamplePlugin;
+
+})(SamplePlugin || {});
+
+hawtioPluginLoader.addModule(SamplePlugin.pluginName);
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/freenode.txt" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/freenode.txt"
new file mode 100755
index 0000000..d30573f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/freenode.txt"
@@ -0,0 +1,2 @@
+skjCBPwx
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/README.md"
new file mode 100755
index 0000000..efff72d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/README.md"
@@ -0,0 +1,21 @@
+# Hawtio executable JAR
+
+You can run hawtio on your machine using the hawtio-app executable JAR.
+
+Once you have built it, just run this from the command line:
+
+ java -jar hawtio-app-x.y.z.jar
+
+Note: If you launch Hawtio with Java 9, add the specified modules to avoid errors on startup and allow attaching to other Java processes:
+
+ java --add-modules jdk.attach,java.xml.bind -jar hawtio-app-x.y.z.jar
+
+The console should show you which URL to open, which by default is [http://localhost:8080/hawtio/](http://localhost:8080/hawtio/).
+
+To set a different port number, run:
+
+ java -jar hawtio-app-x.y.z.jar --port 8090
+
+To see the full list of configuration options, run:
+
+ java -jar hawtio-app-x.y.z.jar --help
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/pom.xml"
new file mode 100755
index 0000000..ba72a1d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/pom.xml"
@@ -0,0 +1,71 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-app
+ ${project.artifactId}
+ hawtio :: hawtio-app
+
+
+
+ io.hawt
+ hawtio-embedded
+ ${project.version}
+
+
+ io.hawt
+ hawtio-default
+ ${project.version}
+ war
+
+
+ org.keycloak
+ keycloak-jetty94-adapter
+ ${keycloak-version}
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j-version}
+
+
+
+
+
+
+ maven-assembly-plugin
+
+ false
+
+ src/main/assembly/assembly.xml
+
+
+
+ io.hawt.app.App
+
+
+
+
+
+
+ make-assembly
+ package
+
+ single
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/src/main/assembly/assembly.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/src/main/assembly/assembly.xml"
new file mode 100755
index 0000000..904bbf6
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/src/main/assembly/assembly.xml"
@@ -0,0 +1,52 @@
+
+
+ hawtio-app
+
+ jar
+
+ false
+
+
+ src/main/assembly
+
+
+ embedded.properties
+
+
+
+
+
+
+ true
+
+
+ io.hawt:hawtio-app
+ io.hawt:hawtio-embedded
+ org.eclipse.jetty:*
+ org.slf4j:*
+ javax.servlet:javax.servlet-api
+
+
+
+
+
+
+ hawtio.war
+
+ io.hawt:hawtio-default
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/src/main/java/io/hawt/app/App.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/src/main/java/io/hawt/app/App.java"
new file mode 100755
index 0000000..f12d793
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-app/src/main/java/io/hawt/app/App.java"
@@ -0,0 +1,160 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.app;
+
+import java.awt.*;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+
+import io.hawt.embedded.Main;
+
+public class App {
+ private static final String WAR_FILENAME = "hawtio.war";
+ private static final int KB = 1024;
+
+ public static void main(String[] args) {
+
+ Object val = System.getProperty("hawtio.authenticationEnabled");
+ if (val == null) {
+ System.setProperty("hawtio.authenticationEnabled", "false");
+ }
+
+ Main main = new Main();
+
+ try {
+ String virtualMachineClass = "com.sun.tools.attach.VirtualMachine";
+ try {
+ loadClass(virtualMachineClass, App.class.getClassLoader(), Thread.currentThread().getContextClassLoader());
+ } catch (Exception e) {
+ // lets try find the tools.jar instead
+ Set paths = new HashSet<>();
+ String javaHome = System.getProperty("java.home", ".");
+ addPath(paths, javaHome);
+
+ // now lets try the JAVA_HOME environment variable just in case
+ javaHome = System.getenv("JAVA_HOME");
+ if (javaHome != null && javaHome.length() > 0) {
+ addPath(paths, javaHome);
+ }
+
+ boolean found = false;
+ for (String path : paths) {
+ File file = new File(path, "lib/tools.jar");
+ if (file.exists()) {
+ found = true;
+ String url = file.toURI().toURL().toString();
+ main.setExtraClassPath(url);
+ break;
+ }
+ }
+ if (!found) {
+ System.err.println(String.format(
+ "Failed to load class %s and find tools.jar in directories %s. %s",
+ virtualMachineClass, paths, e));
+ }
+ }
+
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ URL resource = classLoader.getResource(WAR_FILENAME);
+ if (resource == null) {
+ System.err.println(String.format("Could not find the %s on classpath!", WAR_FILENAME));
+ System.exit(1);
+ }
+ File warFile = File.createTempFile("hawtio-", ".war");
+ writeStreamTo(resource.openStream(), new FileOutputStream(warFile), 64 * KB);
+
+ String warPath = warFile.getCanonicalPath();
+ main.setWar(warPath);
+ } catch (Exception e) {
+ System.err.println("Failed to create hawtio: " + e.getMessage());
+ e.printStackTrace();
+ return;
+ }
+
+ if (!main.parseArguments(args) || main.isHelp()) {
+ main.showOptions();
+ } else {
+ try {
+ main.run();
+
+ // should we open the url
+ int port = main.getPort();
+ String url = "http://localhost:" + port + main.getContextPath();
+ // set what is the url
+ System.setProperty("hawtio.url", url);
+
+ String open = main.isOpenUrl() ? "true" : "false";
+ // JVM system override the main option
+ boolean openUrl = "true".equals(System.getProperty("hawtio.openUrl", open));
+ if (openUrl && Desktop.isDesktopSupported()) {
+ try {
+ Desktop.getDesktop().browse(new URI(url));
+ } catch (Exception e) {
+ System.err.println(String.format(
+ "Failed to open browser session, to access hawtio visit \"%s\"",
+ url));
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("Failed running hawtio: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ protected static void addPath(Set paths, String path) {
+ paths.add(path);
+ String jreSuffix = File.separator + "jre";
+ if (path.endsWith(jreSuffix)) {
+ path = path.substring(0, path.length() - jreSuffix.length());
+ paths.add(path);
+ }
+ }
+
+ private static Class> loadClass(String name, ClassLoader... classLoaders) throws ClassNotFoundException {
+ for (ClassLoader classLoader : classLoaders) {
+ try {
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ }
+ return Class.forName(name);
+ }
+
+ public static int writeStreamTo(final InputStream input, final OutputStream output, int bufferSize) throws IOException {
+ int available = Math.min(input.available(), 256 * KB);
+ byte[] buffer = new byte[Math.max(bufferSize, available)];
+ int answer = 0;
+ int count = input.read(buffer);
+ while (count >= 0) {
+ output.write(buffer, 0, count);
+ answer += count;
+ count = input.read(buffer);
+ }
+ return answer;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/.gitignore" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/.gitignore"
new file mode 100755
index 0000000..072a31e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/.gitignore"
@@ -0,0 +1,4 @@
+hawtio-config
+hawtio.log
+overlays
+mavenIndexer
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/pom.xml"
new file mode 100755
index 0000000..7049cc2
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/pom.xml"
@@ -0,0 +1,133 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-base
+ war
+ ${project.artifactId}
+ hawtio :: Base Web Application
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${servlet-api-version}
+ provided
+
+
+
+ io.hawt
+ hawtio-war
+ ${project.version}
+
+ war
+
+
+
+
+ io.hawt
+ hawtio-core
+ ${project.version}
+ provided
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+ org.apache.aries.blueprint
+ org.apache.aries.blueprint.web
+ ${blueprint-web-version}
+
+
+ org.apache.geronimo.specs
+ geronimo-servlet_2.5_spec
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+
+
+
+
+ ${jetty-plugin-groupId}
+ jetty-maven-plugin
+ ${jetty-version}
+
+ ${project.build.directory}/${project.name}
+ 1
+
+ ${context}
+
+
+
+ ${jettyPort}
+ 60000
+
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat7-maven-plugin
+ 2.0
+
+ 9090
+ ${context}
+
+
+ false
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat6-maven-plugin
+ 2.0
+
+ 9090
+ ${context}
+
+
+ false
+
+
+
+
+
+ maven-clean-plugin
+
+
+
+ ${basedir}/overlays
+
+ **/*.*
+
+ false
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/java/io/hawt/blueprint/HawtioBlueprintContextListener.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/java/io/hawt/blueprint/HawtioBlueprintContextListener.java"
new file mode 100755
index 0000000..7560352
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/java/io/hawt/blueprint/HawtioBlueprintContextListener.java"
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.blueprint;
+
+import org.apache.aries.blueprint.container.BlueprintContainerImpl;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Initialises all the blueprint XML files called META-INF/blueprint.xml on the classpath
+ */
+public class HawtioBlueprintContextListener implements ServletContextListener {
+
+ public static final String CONTAINER_ATTRIBUTE = "org.apache.aries.blueprint.container";
+
+ public static final String LOCATION = "blueprintLocation";
+
+ public static final String PROPERTIES = "blueprintProperties";
+
+ public static final String DEFAULT_LOCATION = "META-INF/blueprint.xml";
+
+ public void contextInitialized(ServletContextEvent event) {
+ ServletContext servletContext = event.getServletContext();
+ String location = servletContext.getInitParameter(LOCATION);
+ if (location == null) {
+ location = DEFAULT_LOCATION;
+ }
+ List resourcePaths = new ArrayList();
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Enumeration resources = classLoader.getResources(location);
+ while (resources.hasMoreElements()) {
+ resourcePaths.add(resources.nextElement());
+ }
+ Collections.sort(resourcePaths, new Comparator() {
+ @Override
+ public int compare(URL o1, URL o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ });
+ servletContext.log("Loading Blueprint contexts " + resourcePaths);
+
+ Map properties = new HashMap();
+ String propLocations = servletContext.getInitParameter(PROPERTIES);
+ if (propLocations != null) {
+ for (String propLoc : propLocations.split(",")) {
+ Enumeration propUrl = classLoader.getResources(propLoc);
+ while (propUrl.hasMoreElements()) {
+ URL url = propUrl.nextElement();
+ InputStream is = url.openStream();
+ try {
+ Properties props = new Properties();
+ props.load(is);
+ Enumeration names = props.propertyNames();
+ while (names.hasMoreElements()) {
+ String key = names.nextElement().toString();
+ properties.put(key, props.getProperty(key));
+ }
+ } finally {
+ is.close();
+ }
+ }
+ }
+ }
+ appendEnvironmentVariablesAndSystemProperties(servletContext, properties);
+
+ BlueprintContainerImpl container = new BlueprintContainerImpl(classLoader, resourcePaths, properties, true);
+ servletContext.setAttribute(CONTAINER_ATTRIBUTE, container);
+ } catch (Exception e) {
+ servletContext.log("Failed to startup blueprint container. " + e, e);
+ }
+ }
+
+ protected void appendEnvironmentVariablesAndSystemProperties(ServletContext servletContext, Map properties) {
+ try {
+ Properties sysProperties = System.getProperties();
+ Set> sysEntries = sysProperties.entrySet();
+ for (Map.Entry sysEntry : sysEntries) {
+ Object key = sysEntry.getKey();
+ Object value = sysEntry.getValue();
+ if (key != null && value != null) {
+ String propertyName = key.toString();
+ String propertyValue = value.toString();
+ if (!properties.containsKey(propertyName)) {
+ properties.put(propertyName, propertyValue);
+ }
+ }
+ }
+ Map env = System.getenv();
+ if (env != null) {
+ Set> entries = env.entrySet();
+ for (Map.Entry entry : entries) {
+ String name = entry.getKey();
+ String propertyName = convertEnvironmentVariableToSystemProperty(name);
+ properties.put(propertyName, entry.getValue());
+ }
+ }
+ } catch (Exception e) {
+ servletContext.log("Failed to load environment variables: " + e, e);
+ }
+ }
+
+ protected String convertEnvironmentVariableToSystemProperty(String name) {
+ // system properties may be upper and lower case so lets not mess with the case
+ // lets convert _ to dots so that folks can specify dots in env vars
+ return name.replace('_', '.');
+ }
+
+ public void contextDestroyed(ServletContextEvent event) {
+ ServletContext servletContext = event.getServletContext();
+ Object container = servletContext.getAttribute(CONTAINER_ATTRIBUTE);
+ if (container instanceof BlueprintContainerImpl) {
+ BlueprintContainerImpl blueprint = (BlueprintContainerImpl) container;
+ blueprint.destroy();
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/resources/blueprint.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/resources/blueprint.properties"
new file mode 100755
index 0000000..eb065e3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/resources/blueprint.properties"
@@ -0,0 +1,5 @@
+# the properties file used to override blueprint configuration properties:
+#�http://aries.apache.org/modules/blueprintweb.html
+#
+# for hawtio configuration options see:
+# https://github.com/hawtio/hawtio/blob/master/docs/Configuration.md
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/resources/log4j.properties"
new file mode 100755
index 0000000..e0d1274
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/resources/log4j.properties"
@@ -0,0 +1,14 @@
+log4j.rootLogger=INFO, console
+
+# Console will only display warnnings
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n
+log4j.appender.console.threshold=INFO
+
+# File appender will contain all info messages
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n
+log4j.appender.file.file=${user.home}/.hawtio/logs/hawtio.log
+log4j.appender.file.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/webapp/WEB-INF/web.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/webapp/WEB-INF/web.xml"
new file mode 100755
index 0000000..8977a64
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-base/src/main/webapp/WEB-INF/web.xml"
@@ -0,0 +1,301 @@
+
+
+
+ hawtio
+ hawtio
+
+
+ Enable/disable hawtio's authentication filter, value is really a boolean
+ hawtio/authenticationEnabled
+ java.lang.String
+ false
+
+
+
+ Authorized user role, empty string disables authorization
+ hawtio/role
+ java.lang.String
+
+
+
+
+ JAAS classname that would contain the role principal, empty string disables authorization
+ hawtio/rolePrincipalClasses
+ java.lang.String
+
+
+
+
+ JAAS realm used to authenticate users
+ hawtio/realm
+ java.lang.String
+ *
+
+
+
+ AuthenticationContainerDiscovery classes divided by comma, used to discover container environments
+ hawtio/authenticationContainerDiscoveryClasses
+ java.lang.String
+ io.hawt.web.tomcat.TomcatAuthenticationContainerDiscovery
+
+
+
+ Enable/disable Keycloak integration. Value is really a boolean
+ hawtio/keycloakEnabled
+ java.lang.String
+ false
+
+
+
+ Keycloak config file used for frontend. Will use default location if not provided
+ hawtio/keycloakClientConfig
+ java.lang.String
+
+
+
+
+ The maximum time interval, in seconds, that the servlet container will keep this session open between client accesses.
+ hawtio/sessionTimeout
+ java.lang.String
+
+
+
+
+ SessionExpiryFilter
+ io.hawt.web.auth.SessionExpiryFilter
+
+
+ SessionExpiryFilter
+ /*
+
+
+
+ cache
+ io.hawt.web.filters.CacheHeadersFilter
+
+
+ cache
+ /*
+
+
+
+ CORSFilter
+ io.hawt.web.filters.CORSFilter
+
+
+ CORSFilter
+ /*
+
+
+
+ XFrameOptionsFilter
+ io.hawt.web.filters.XFrameOptionsFilter
+
+
+ XFrameOptionsFilter
+ /*
+
+
+
+ XXSSProtectionFilter
+ io.hawt.web.filters.XXSSProtectionFilter
+
+
+ XXSSProtectionFilter
+ /*
+
+
+
+ XContentTypeOptionsFilter
+ io.hawt.web.filters.XContentTypeOptionsFilter
+
+
+ XContentTypeOptionsFilter
+ /*
+
+
+
+ ContentSecurityPolicyFilter
+ io.hawt.web.filters.ContentSecurityPolicyFilter
+
+
+ ContentSecurityPolicyFilter
+ /*
+
+
+
+ StrictTransportSecurityFilter
+ io.hawt.web.filters.StrictTransportSecurityFilter
+
+
+ StrictTransportSecurityFilter
+ /*
+
+
+
+ PublicKeyPinningFilter
+ io.hawt.web.filters.PublicKeyPinningFilter
+
+
+ PublicKeyPinningFilter
+ /*
+
+
+
+ AuthenticationFilter
+ io.hawt.web.auth.AuthenticationFilter
+
+
+ AuthenticationFilter
+ /jolokia/*
+
+
+
+ LoginRedirectFilter
+ io.hawt.web.auth.LoginRedirectFilter
+
+
+ LoginRedirectFilter
+ /*
+
+
+
+ BaseTagHrefFilter
+ io.hawt.web.filters.BaseTagHrefFilter
+
+
+ BaseTagHrefFilter
+ /
+ /index.html
+ /login.html
+ ERROR
+ FORWARD
+ REQUEST
+
+
+
+ jolokia-agent
+ io.hawt.web.servlets.JolokiaConfiguredAgentServlet
+
+ mbeanQualifier
+ qualifier=hawtio
+
+
+
+ allowErrorDetails
+ false
+
+
+ includeStackTrace
+ false
+
+
+ restrictorClass
+ io.hawt.system.RBACRestrictor
+
+ 1
+
+
+
+ jolokia-agent
+ /jolokia/*
+
+
+
+ jolokia-proxy
+ io.hawt.web.proxy.ProxyServlet
+
+
+ proxyWhitelist
+
+ localhost,
+ 127.0.0.1
+
+
+ 1
+
+
+ jolokia-proxy
+ /proxy/*
+
+
+
+ user
+ io.hawt.web.auth.keycloak.KeycloakUserServlet
+
+
+ user
+ /user/*
+
+
+
+ login
+ io.hawt.web.auth.LoginServlet
+
+
+ login
+ /auth/login
+
+
+
+ logout
+ io.hawt.web.auth.LogoutServlet
+
+
+ logout
+ /auth/logout
+
+
+
+ keycloak
+ io.hawt.web.auth.keycloak.KeycloakServlet
+
+
+ keycloak
+ /keycloak/*
+
+
+
+ woff
+ application/font-woff
+
+
+
+ io.hawt.HawtioContextListener
+
+
+
+ io.hawt.blueprint.HawtioBlueprintContextListener
+
+
+
+ blueprintProperties
+ blueprint.properties
+
+
+ blueprintLocation
+ OSGI-INF/blueprint/blueprint.xml
+
+
+
+ 404
+ /index.html
+
+
+
+ index.html
+
+
+
+
+ true
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/.editorconfig" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/.editorconfig"
new file mode 100755
index 0000000..a6d1783
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/.editorconfig"
@@ -0,0 +1,8 @@
+# http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*.{html,ts,js,json,css,less}]
+indent_style = space
+indent_size = 2
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/.gitignore" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/.gitignore"
new file mode 100755
index 0000000..46cd4e6
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/.gitignore"
@@ -0,0 +1,6 @@
+.vscode
+dist
+node
+node_modules
+target
+temp
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/README.md"
new file mode 100755
index 0000000..4be128a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/README.md"
@@ -0,0 +1,42 @@
+# Hawtio console assembly
+
+This assembles all Hawtio v2 components for the Web console for Java.
+
+## Set up development environment
+
+### Clone the repository
+
+ $ git clone https://github.com/hawtio/hawtio
+ $ cd hawtio/hawtio-console-assembly
+
+### Install development tools
+
+* [Node.js](http://nodejs.org)
+* [Yarn](https://yarnpkg.com)
+* [gulp](http://gulpjs.com/)
+
+### Install project dependencies
+
+ $ yarn install
+
+### Run the web application
+
+ $ yarn start
+
+#### To test Keycloak integration
+
+ $ yarn start --keycloak
+
+### Change the default proxy port
+
+To proxy to a local JVM running on a different port than `8181` specify the `--port` CLI arguement to gulp:
+
+ $ gulp --port=8282
+
+### Turn on source maps generation for debugging TypeScript
+
+If you want to debug `.ts` using a browser developer tool such as Chrome DevTools, pass the `--sourcemap` flag to gulp:
+
+ $ gulp --sourcemap
+
+Do not use this flag when you are committing the compiled `.js` file, as it embeds source maps to the output file. Use this flag only during development.
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/package.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/package.json"
new file mode 100755
index 0000000..df1f8a0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/package.json"
@@ -0,0 +1,29 @@
+{
+ "name": "@hawtio/console-assembly",
+ "version": "2.0.0",
+ "dependencies": {
+ "@hawtio/integration": "~4.2.0",
+ "@hawtio/oauth": "~4.1.0",
+ "keycloak-js": "3.4.3"
+ },
+ "flat": true,
+ "resolutions": {
+ "@types/jasmine": "2.8.6",
+ "@types/jqueryui": "1.12.2",
+ "@types/angular": "1.6.43",
+ "@types/jquery": "2.0.49",
+ "@types/marked": "0.3.0",
+ "angular-ui-bootstrap": "2.5.6",
+ "jquery": "2.2.4",
+ "moment": "2.21.0",
+ "bootstrap-select": "1.13.0",
+ "angular": "1.7.3",
+ "angular-animate": "1.7.3",
+ "angular-sanitize": "1.7.3"
+ },
+ "license": "Apache-2.0",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/hawtio/hawtio.git"
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/app.less" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/app.less"
new file mode 100755
index 0000000..4b4274f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/app.less"
@@ -0,0 +1,3 @@
+.navbar-brand-name {
+ max-height: 30px;
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/app.ts" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/app.ts"
new file mode 100755
index 0000000..75776a2
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/app.ts"
@@ -0,0 +1,39 @@
+///
+
+namespace ConsoleAssembly {
+
+ const pluginName = 'hawtio-console-assembly';
+ const log: Logging.Logger = Logger.get(pluginName);
+
+ angular
+ .module(pluginName, [
+ Login.loginModule
+ ])
+ .run(refreshUserSessionWhenLocationChanges)
+ .run(configureAbout);
+
+ function refreshUserSessionWhenLocationChanges(
+ locationChangeStartTasks: Core.ParameterizedTasks,
+ $http: ng.IHttpService): void {
+ 'ngInject';
+ locationChangeStartTasks.addTask('RefreshUserSession',
+ ($event: ng.IAngularEvent, newUrl: string, oldUrl: string): void => {
+ $http({
+ method: 'post',
+ url: 'refresh'
+ }).then((response) => {
+ log.debug("Updated session. Response:", response);
+ }).catch((response) => {
+ log.debug("Failed to update session expiry. Response:", response);
+ });
+ });
+ }
+
+ function configureAbout(aboutService: About.AboutService, jolokiaService: JVM.JolokiaService): void {
+ jolokiaService.getAttribute('hawtio:type=About', 'HawtioVersion')
+ .then(hawtioVersion => aboutService.addProductInfo('Hawtio', hawtioVersion));
+ }
+
+ hawtioPluginLoader.addModule(pluginName);
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/hawtconfig.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/hawtconfig.json"
new file mode 100755
index 0000000..59d54ff
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/hawtconfig.json"
@@ -0,0 +1,15 @@
+{
+ "branding": {
+ "appName": "Hawtio Management Console",
+ "appLogoUrl": "img/hawtio-logo.svg",
+ "companyLogoUrl": "img/hawtio-logo.svg"
+ },
+ "about": {
+ "title": "Hawtio Management Console",
+ "productInfo": [],
+ "additionalInfo": "",
+ "copyright": "",
+ "imgSrc": "img/hawtio-logo.svg"
+ },
+ "disabledRoutes": []
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/head-partial.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/head-partial.html"
new file mode 100755
index 0000000..ef0153b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/head-partial.html"
@@ -0,0 +1,133 @@
+
+
+ Hawtio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/img/favicon.ico" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/img/favicon.ico"
new file mode 100755
index 0000000..0cae3ad
Binary files /dev/null and "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/img/favicon.ico" differ
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/index.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/index.html"
new file mode 100755
index 0000000..b5a0807
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/index.html"
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login.html"
new file mode 100755
index 0000000..15f211e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login.html"
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/keycloak-login.ts" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/keycloak-login.ts"
new file mode 100755
index 0000000..f76bc8c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/keycloak-login.ts"
@@ -0,0 +1,68 @@
+///
+
+namespace Login {
+
+ const KEYCLOAK_ENABLED_URL: string = "keycloak/enabled";
+ const KEYCLOAK_CLIENT_CONFIG_URL: string = "keycloak/client-config";
+ const KEYCLOAK_VALIDATE_URL: string = "keycloak/validate-subject-matches";
+
+ hawtioPluginLoader.registerPreBootstrapTask({
+ name: 'KeycloakLoginBootstrap',
+ task: (next) => {
+ log.debug('Executing keycloak login bootstrap task');
+ configureKeycloakIfEnabled(next);
+ }
+ }, true);
+
+ function configureKeycloakIfEnabled(next: () => void): void {
+ $.ajax(KEYCLOAK_ENABLED_URL, {
+ type: "GET",
+ success: (data: any, status: string, xhr: JQueryXHR) => {
+ log.debug("Keycloak enabled:", data);
+ let keycloakEnabled = (data === true || data === "true");
+ if (keycloakEnabled) {
+ loadKeycloakConfig(next);
+ } else {
+ next();
+ }
+ },
+ error: (xhr: JQueryXHR, status: string, error: string) => {
+ log.error("Failed to retrieve keycloak/enabled:", error);
+ next();
+ }
+ });
+ }
+
+ function loadKeycloakConfig(next: () => void): void {
+ $.ajax(KEYCLOAK_CLIENT_CONFIG_URL, {
+ type: "GET",
+ success: (data: any, status: string, xhr: JQueryXHR) => {
+ log.debug("Loaded keycloak/client-config:", data);
+
+ // This enables hawtio-oauth keycloak integration
+ HawtioKeycloak.config = data;
+ next();
+ },
+ error: (xhr: JQueryXHR, status: string, error: string) => {
+ log.error("Failed to retrieve keycloak/client-config:", error);
+ next();
+ }
+ });
+ }
+
+ // TODO: validate subject against server session
+ function validateSubjectMatches(keycloakUser: string): void {
+ let keycloakValidateUrl: string = `${KEYCLOAK_VALIDATE_URL}?keycloakUser=${encodeURIComponent(keycloakUser)}`;
+
+ $.ajax(keycloakValidateUrl, {
+ type: "GET",
+ success: (data: any, status: string, xhr: JQueryXHR) => {
+ log.debug("Got response for validate subject matches:", data);
+ },
+ error: (xhr: JQueryXHR, status: string, error: string) => {
+ log.debug("Failed to validate subject matches:", error);
+ }
+ });
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.component.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.component.html"
new file mode 100755
index 0000000..71d49e4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.component.html"
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
{{$ctrl.branding.appType}}
+
+
+
+ Incorrect username or password
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.component.ts" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.component.ts"
new file mode 100755
index 0000000..886d3ce
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.component.ts"
@@ -0,0 +1,52 @@
+namespace Login {
+
+ const LOGIN_URL: string = 'auth/login';
+
+ export class LoginController {
+ branding = {};
+ entity = {
+ username: '',
+ password: ''
+ };
+ wrongPassword: boolean = false;
+
+ constructor(
+ private $http: ng.IHttpService,
+ private $window: ng.IWindowService,
+ private documentBase: string) {
+ 'ngInject';
+ }
+
+ $onInit(): void {
+ // fetch hawtconfig.json
+ this.$http.get('hawtconfig.json').then(
+ (response: ng.IHttpResponse) => {
+ log.debug('hawtconfig.json:', response.data);
+ this.branding = response.data.branding;
+ },
+ (response) => {
+ log.warn('Failed to fetch hawtconfig.json', response);
+ });
+ }
+
+ doLogin(): void {
+ if (this.entity.username.trim() == '') {
+ return;
+ }
+ this.$http.post(LOGIN_URL, this.entity).then(
+ (response: ng.IHttpResponse) => {
+ log.debug("Server login success:", response.data);
+ this.$window.location.href = this.documentBase;
+ },
+ (response) => {
+ log.error('Failed to log in', response);
+ this.wrongPassword = true;
+ });
+ }
+ }
+
+ export const loginComponent: angular.IComponentOptions = {
+ controller: LoginController,
+ templateUrl: 'app/src/login/login.component.html'
+ };
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.config.ts" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.config.ts"
new file mode 100755
index 0000000..0ac5df1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.config.ts"
@@ -0,0 +1,56 @@
+///
+///
+
+namespace Login {
+
+ const USER_URL: string = 'user';
+ const AUTH_LOGOUT_URL: string = 'auth/logout';
+
+ export function init(authService: Core.AuthService, keycloakService: HawtioKeycloak.KeycloakService,
+ postLogoutTasks: Core.Tasks, $window: ng.IWindowService, HawtioExtension: Core.HawtioExtension,
+ $compile: ng.ICompileService): void {
+ 'ngInject';
+
+ if (keycloakService.enabled) {
+ // When Keycloak is enabled, login/logout is handled at hawtio-oauth keycloak plugin
+ return;
+ }
+
+ // Get logged-in user from server session
+ $.ajax(USER_URL, {
+ type: "GET",
+ success: (username: any, status: string, xhr: JQueryXHR) => {
+ log.debug("Logged-in user:", username);
+
+ authService.login(username, null);
+
+ if (!authService.isDefaultUser()) {
+ registerPostLogoutTasks(postLogoutTasks, $window);
+ addLogoutLink(authService, HawtioExtension, $compile);
+ }
+ },
+ error: (xhr: JQueryXHR, status: string, error: string) => {
+ // Silently ignore as mostly it's just not logged-in yet
+ log.debug("Failed to get logged-in user from server", error);
+ }
+ });
+ }
+
+ function registerPostLogoutTasks(postLogoutTasks: Core.Tasks, $window: ng.IWindowService) {
+ log.debug("Register 'DefaultLogout' to postLogoutTasks");
+ postLogoutTasks.addTask('DefaultLogout', () => {
+ log.debug("Log out, redirecting to:", AUTH_LOGOUT_URL);
+ $window.location.href = AUTH_LOGOUT_URL;
+ });
+ }
+
+ function addLogoutLink(authService: Core.AuthService, HawtioExtension: Core.HawtioExtension,
+ $compile: ng.ICompileService) {
+ HawtioExtension.add('hawtio-logout', ($scope) => {
+ $scope.authService = authService;
+ let template = 'Logout ';
+ return $compile(template)($scope);
+ });
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.less" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.less"
new file mode 100755
index 0000000..fec5b13
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.less"
@@ -0,0 +1,12 @@
+.login-pf #brand img {
+ display: inline-block;
+ height: auto;
+ padding: 0 5px 7px 0;
+}
+.login-pf #brand span {
+ font-size: 18px;
+ font-weight: bold;
+ vertical-align: bottom;
+ text-transform: uppercase;
+ color: #c0c0c0;
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.module.ts" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.module.ts"
new file mode 100755
index 0000000..2e5328a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/src/login/login.module.ts"
@@ -0,0 +1,14 @@
+///
+///
+
+namespace Login {
+
+ export const loginModule = angular
+ .module('hawtio-login', [])
+ .component('hawtioLogin', loginComponent)
+ .run(init)
+ .name;
+
+ export const log = Logger.get(loginModule);
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/yarn.lock" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/yarn.lock"
new file mode 100755
index 0000000..7689e42
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/app/yarn.lock"
@@ -0,0 +1,746 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@hawtio/core-dts@3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@hawtio/core-dts/-/core-dts-3.2.0.tgz#9a685349dcfb9733234f6de71da5005d69b613fb"
+ dependencies:
+ "@types/jquery" "~2.0.46"
+
+"@hawtio/core@~4.1.0":
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/@hawtio/core/-/core-4.1.3.tgz#7afb1bb43bc944579ccbef76b517f40a94e9752b"
+ dependencies:
+ "@hawtio/core-dts" "3.2.0"
+ "@types/angular" "*"
+ "@types/angular-route" "*"
+ "@types/jasmine" "2.8.2"
+ "@types/jquery" "~2.0.0"
+ "@types/lodash" "^4.0.0"
+ "@types/marked" "0.3.0"
+ "@types/urijs" "1.15.34"
+ angular "~1.7.0"
+ angular-animate "~1.7.0"
+ angular-patternfly "^4.0.0"
+ angular-route "~1.7.0"
+ angular-sanitize "~1.7.0"
+ gulp-rename "~1.2.3"
+ jquery "2.2.4"
+ js-logger "1.4.1"
+ lodash "~4.17.0"
+ marked "0.3.9"
+ urijs "1.19.0"
+
+"@hawtio/forms@~4.1.0":
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/@hawtio/forms/-/forms-4.1.0.tgz#1bf89334e8cdf787661f2b38e788e3053dc7eef0"
+ dependencies:
+ "@hawtio/ui" "~4.1.0"
+
+"@hawtio/integration@~4.2.0":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@hawtio/integration/-/integration-4.2.1.tgz#26025f5e67e19e1de2ac7ac68aea2516c42492b1"
+ dependencies:
+ "@hawtio/jmx" "~4.2.0"
+ "@types/angular-mocks" "~1.7.0"
+ "@types/angular-ui-bootstrap" "~0.13.46"
+ "@types/jqueryui" "1.12.2"
+ dagre-layout "0.8.0"
+ ng-infinite-scroll "1.3.0"
+
+"@hawtio/jmx@~4.2.0":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@hawtio/jmx/-/jmx-4.2.1.tgz#c47fad08216b42769593605c83d84de397a1d2af"
+ dependencies:
+ "@hawtio/core" "~4.1.0"
+ "@hawtio/forms" "~4.1.0"
+ "@hawtio/ui" "~4.1.0"
+ "@types/angular-ui-bootstrap" "~0.13.46"
+ angular-resizable "1.2.0"
+ cubism "^1.6.0"
+ jolokia.js "^1.6.0-1"
+ patternfly-bootstrap-treeview "~2.1.0"
+
+"@hawtio/oauth@~4.1.0":
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/@hawtio/oauth/-/oauth-4.1.0.tgz#18340083bf6f9ced3f1207f3eb3912b64a34f477"
+ dependencies:
+ "@hawtio/core" "~4.1.0"
+ ng-idle "^1.3.2"
+
+"@hawtio/ui@~4.1.0":
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/@hawtio/ui/-/ui-4.1.0.tgz#c7d26dfa8e54f7a8e418eb872074e1821cf2bb54"
+ dependencies:
+ "@hawtio/core" "~4.1.0"
+ "@types/bootstrap" "3.3.36"
+ "@types/clipboard" "1.5.35"
+ "@types/codemirror" "0.0.40"
+ "@types/js-beautify" "0.0.30"
+ "@types/marked" "0.0.28"
+ angular-ui-bootstrap "2.5.6"
+ clipboard "1.7.1"
+ codemirror "5.33.0"
+ js-beautify "1.7.5"
+
+"@types/angular-mocks@~1.7.0":
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/@types/angular-mocks/-/angular-mocks-1.7.0.tgz#310d999a3c47c10ecd8eef466b5861df84799429"
+ dependencies:
+ "@types/angular" "*"
+
+"@types/angular-route@*":
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/@types/angular-route/-/angular-route-1.7.0.tgz#ba12d09df1aac3c88e3684500001daedfc97fb69"
+ dependencies:
+ "@types/angular" "*"
+
+"@types/angular-ui-bootstrap@~0.13.46":
+ version "0.13.47"
+ resolved "https://registry.yarnpkg.com/@types/angular-ui-bootstrap/-/angular-ui-bootstrap-0.13.47.tgz#e9fd4baf09dd98ff2b868ed00474310b2a66fa37"
+ dependencies:
+ "@types/angular" "*"
+
+"@types/angular@*", "@types/angular@1.6.43":
+ version "1.6.43"
+ resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.6.43.tgz#6235ef416053a86302970717510a936d889cbb9a"
+
+"@types/bootstrap@3.3.36":
+ version "3.3.36"
+ resolved "https://registry.yarnpkg.com/@types/bootstrap/-/bootstrap-3.3.36.tgz#5ca0b81655427398fe7c8728bccdc395069093d0"
+ dependencies:
+ "@types/jquery" "*"
+
+"@types/c3@^0.6.0":
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/@types/c3/-/c3-0.6.2.tgz#b4d5fc5dbe05b900a531544786f8cfedf5b8e416"
+ dependencies:
+ "@types/d3" "^4"
+
+"@types/clipboard@1.5.35":
+ version "1.5.35"
+ resolved "https://registry.yarnpkg.com/@types/clipboard/-/clipboard-1.5.35.tgz#bceb67a7e0aad3070468929b95a2d626405db464"
+
+"@types/codemirror@0.0.40":
+ version "0.0.40"
+ resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.40.tgz#0868ed9ba5bf3ef8072de80e245ecf4a8f0bbdfd"
+
+"@types/d3-array@*":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-1.2.4.tgz#7088445c8717ba1fba416a1df7bbd11cc72a3763"
+
+"@types/d3-axis@*":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-1.0.11.tgz#efd975f9fec14c2afd03828f3acec0ef97d37c3b"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-brush@*":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-1.0.9.tgz#c71070845946eeee4cf330e04123a3997e6476bf"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-chord@*":
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-1.0.8.tgz#08c0fbb10281be0a5b3fdf48c9c081af02f79fb6"
+
+"@types/d3-collection@*":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-collection/-/d3-collection-1.0.7.tgz#829e1db477d6bbbcdc038cbc489f22798752d707"
+
+"@types/d3-color@*":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.2.1.tgz#26141c3c554e320edd40726b793570a3ae57397e"
+
+"@types/d3-dispatch@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-1.0.6.tgz#19b173f669cd2ab7dd3d862e8037aae1a98c7508"
+
+"@types/d3-drag@*":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-1.2.2.tgz#1cdd7716212a8cdef0a24c782c9d86c6aeb4a451"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-dsv@*":
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-1.0.34.tgz#b7b3c75653a31b1e2555c9c0300a6eaf12a5b6fd"
+
+"@types/d3-ease@*":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-1.0.7.tgz#93a301868be9e15061f3d44343b1ab3f8acb6f09"
+
+"@types/d3-force@*":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-1.1.1.tgz#185c18b77932df63457894bd36d0d6e9692546c0"
+
+"@types/d3-format@*":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-1.3.0.tgz#c5e115fac8e6861ce656fe9861892b22f6b0cfcb"
+
+"@types/d3-geo@*":
+ version "1.10.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-1.10.3.tgz#3c01b2baa480e1108301096328dc2837e7ff4d8a"
+ dependencies:
+ "@types/geojson" "*"
+
+"@types/d3-hierarchy@*":
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.4.tgz#b04dfcb1f2074da789ada10fe4942d13f0bce421"
+
+"@types/d3-interpolate@*":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-1.3.0.tgz#65b9627900bfdd82474875d9b23d574a4388af7c"
+ dependencies:
+ "@types/d3-color" "*"
+
+"@types/d3-path@*":
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.7.tgz#a0736fceed688a695f48265a82ff7a3369414b81"
+
+"@types/d3-polygon@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-1.0.6.tgz#db25c630a2afb9191fe51ba61dd37baee9dd44c7"
+
+"@types/d3-quadtree@*":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-1.0.6.tgz#45da9e603688ba90eedd3d40f6e504764e06e493"
+
+"@types/d3-queue@*":
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-queue/-/d3-queue-3.0.7.tgz#94dc7af693281ab78ccdf381a8c1f71ef16659c1"
+
+"@types/d3-random@*":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-1.1.1.tgz#38647ce2ff4ce7d0d56974334c1c4092513c8b9f"
+
+"@types/d3-request@*":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-request/-/d3-request-1.0.3.tgz#f528d12efdc83dbc3df486746c939fc5519dc79c"
+ dependencies:
+ "@types/d3-dsv" "*"
+
+"@types/d3-scale@^1":
+ version "1.0.14"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-1.0.14.tgz#4544e4eb61e3712dacaba9dd8910e745bb7a9840"
+ dependencies:
+ "@types/d3-time" "*"
+
+"@types/d3-selection@*":
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-1.3.4.tgz#2f9b71e25fb73bc95c3842dd52b7e6d523292896"
+
+"@types/d3-shape@*":
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.2.6.tgz#5badbbf4f29f9ca91e847506aa2241db757adccb"
+ dependencies:
+ "@types/d3-path" "*"
+
+"@types/d3-time-format@*":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-2.1.0.tgz#011e0fb7937be34a9a8f580ae1e2f2f1336a8a22"
+
+"@types/d3-time@*":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.0.9.tgz#c2cf05a3cd51f810b8d8a9bbca0c74030d4e535e"
+
+"@types/d3-timer@*":
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-1.0.8.tgz#a3441d9605367059e14ad8c3494132143cbc8d58"
+
+"@types/d3-transition@*":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-1.1.3.tgz#efcf4941dae22135d595514ba488f4f370d396b0"
+ dependencies:
+ "@types/d3-selection" "*"
+
+"@types/d3-voronoi@*":
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/@types/d3-voronoi/-/d3-voronoi-1.1.8.tgz#a039cb8368bce4efc1a70aebe744d210851cf1a7"
+
+"@types/d3-zoom@*":
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-1.7.2.tgz#ee67f063199c179949d83b6b1e6166207de5f06e"
+ dependencies:
+ "@types/d3-interpolate" "*"
+ "@types/d3-selection" "*"
+
+"@types/d3@^4":
+ version "4.13.1"
+ resolved "https://registry.yarnpkg.com/@types/d3/-/d3-4.13.1.tgz#6d12ecab1ceb704fb41e4ac43e1c45f7fef016c8"
+ dependencies:
+ "@types/d3-array" "*"
+ "@types/d3-axis" "*"
+ "@types/d3-brush" "*"
+ "@types/d3-chord" "*"
+ "@types/d3-collection" "*"
+ "@types/d3-color" "*"
+ "@types/d3-dispatch" "*"
+ "@types/d3-drag" "*"
+ "@types/d3-dsv" "*"
+ "@types/d3-ease" "*"
+ "@types/d3-force" "*"
+ "@types/d3-format" "*"
+ "@types/d3-geo" "*"
+ "@types/d3-hierarchy" "*"
+ "@types/d3-interpolate" "*"
+ "@types/d3-path" "*"
+ "@types/d3-polygon" "*"
+ "@types/d3-quadtree" "*"
+ "@types/d3-queue" "*"
+ "@types/d3-random" "*"
+ "@types/d3-request" "*"
+ "@types/d3-scale" "^1"
+ "@types/d3-selection" "*"
+ "@types/d3-shape" "*"
+ "@types/d3-time" "*"
+ "@types/d3-time-format" "*"
+ "@types/d3-timer" "*"
+ "@types/d3-transition" "*"
+ "@types/d3-voronoi" "*"
+ "@types/d3-zoom" "*"
+
+"@types/geojson@*":
+ version "7946.0.4"
+ resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.4.tgz#4e049756383c3f055dd8f3d24e63fb543e98eb07"
+
+"@types/jasmine@2.8.2", "@types/jasmine@2.8.6":
+ version "2.8.6"
+ resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.6.tgz#14445b6a1613cf4e05dd61c3c3256d0e95c0421e"
+
+"@types/jquery@*", "@types/jquery@2.0.49", "@types/jquery@~2.0.0", "@types/jquery@~2.0.46":
+ version "2.0.49"
+ resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-2.0.49.tgz#95bd7064caebf65bde10429dff491a1aea05b67d"
+
+"@types/jqueryui@1.12.2":
+ version "1.12.2"
+ resolved "https://registry.yarnpkg.com/@types/jqueryui/-/jqueryui-1.12.2.tgz#8daa7ffa16880c78b1662ff287df058a2aceb651"
+ dependencies:
+ "@types/jquery" "*"
+
+"@types/js-beautify@0.0.30":
+ version "0.0.30"
+ resolved "https://registry.yarnpkg.com/@types/js-beautify/-/js-beautify-0.0.30.tgz#82ffbeb2c2dec592f1d04169e926912eeed567ec"
+
+"@types/lodash@^4.0.0":
+ version "4.14.118"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.118.tgz#247bab39bfcc6d910d4927c6e06cbc70ec376f27"
+
+"@types/marked@0.0.28", "@types/marked@0.3.0":
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.3.0.tgz#583c223dd33385a1dda01aaf77b0cd0411c4b524"
+
+"@types/urijs@1.15.34":
+ version "1.15.34"
+ resolved "https://registry.yarnpkg.com/@types/urijs/-/urijs-1.15.34.tgz#b9d5954e9beaabb6fc48c2127d8df15ac6393256"
+ dependencies:
+ "@types/jquery" "*"
+
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+
+angular-animate@1.5.*, angular-animate@1.7.3, angular-animate@~1.7.0:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/angular-animate/-/angular-animate-1.7.3.tgz#99aa794d3417aa6a794f603c9c27ec0ee4c4b3b4"
+
+angular-drag-and-drop-lists@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/angular-drag-and-drop-lists/-/angular-drag-and-drop-lists-2.0.0.tgz#a01d44b94cf233c9c2d45a31842cb35a9d0882ca"
+
+angular-patternfly@^4.0.0:
+ version "4.18.6"
+ resolved "https://registry.yarnpkg.com/angular-patternfly/-/angular-patternfly-4.18.6.tgz#4f62fc235d93aecd1c03f7ed70e08ec1ea2e5fdb"
+ dependencies:
+ angular "1.5.*"
+ angular-animate "1.5.*"
+ angular-sanitize "1.5.*"
+ angular-svg-base-fix "2.0.0"
+ angular-ui-bootstrap "2.3.x"
+ lodash "4.x"
+ patternfly "^3.37.1"
+ optionalDependencies:
+ angular-drag-and-drop-lists "2.0.0"
+ angularjs-datatables "^0.5.9"
+ bootstrap "~3.3.7"
+ bootstrap-select "~1.12.4"
+ c3 "~0.4.11"
+ d3 "~3.5.17"
+ datatables.net "^1.10.12"
+ datatables.net-select "~1.2.0"
+ jquery "~3.2.1"
+ jquery-ui-dist "~1.12.1"
+ moment "~2.19.3"
+
+angular-resizable@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/angular-resizable/-/angular-resizable-1.2.0.tgz#9dd29af008f8b54abfc051bd269a8f0b4fe43f1a"
+
+angular-route@~1.7.0:
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/angular-route/-/angular-route-1.7.5.tgz#34a3648c407a14a030d075cf485318e33ba23f0e"
+
+angular-sanitize@1.5.*, angular-sanitize@1.7.3, angular-sanitize@~1.7.0:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/angular-sanitize/-/angular-sanitize-1.7.3.tgz#e1ddaa7337724f9554066fd9e9123486b8881c4a"
+
+angular-svg-base-fix@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/angular-svg-base-fix/-/angular-svg-base-fix-2.0.0.tgz#f3d5f85b87a10d21310f47da8455038b90cfb000"
+
+angular-ui-bootstrap@2.3.x, angular-ui-bootstrap@2.5.6:
+ version "2.5.6"
+ resolved "https://registry.yarnpkg.com/angular-ui-bootstrap/-/angular-ui-bootstrap-2.5.6.tgz#23937322ec641a6fbee16498cc32452aa199e7c5"
+
+angular@1.5.*, angular@1.7.3, angular@>=1.3.0, angular@^1.2.0, angular@~1.7.0:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/angular/-/angular-1.7.3.tgz#0f25a661d079fc84d5ccc877a2ef9d7178575ddb"
+
+angularjs-datatables@^0.5.9:
+ version "0.5.9"
+ resolved "https://registry.yarnpkg.com/angularjs-datatables/-/angularjs-datatables-0.5.9.tgz#24bdc3ba0951741f4172295b6a795c58ce63ad94"
+ dependencies:
+ angular ">=1.3.0"
+ datatables.net "^1.10.11"
+ datatables.net-dt "^1.10.11"
+ jquery ">=1.11.0"
+
+bluebird@^3.0.5:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
+
+bootstrap-datepicker@^1.7.1:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/bootstrap-datepicker/-/bootstrap-datepicker-1.8.0.tgz#c63513931e6f09f16ae9f11b62f32d950df3958e"
+ dependencies:
+ jquery ">=1.7.1 <4.0.0"
+
+bootstrap-sass@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/bootstrap-sass/-/bootstrap-sass-3.3.7.tgz#6596c7ab40f6637393323ab0bc80d064fc630498"
+
+bootstrap-select@1.12.2, bootstrap-select@1.13.0, bootstrap-select@~1.12.4:
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.13.0.tgz#f31d0a23fc6070fd5b17b841bf1ca115ce54775b"
+
+bootstrap-slider@^9.9.0:
+ version "9.10.0"
+ resolved "https://registry.yarnpkg.com/bootstrap-slider/-/bootstrap-slider-9.10.0.tgz#1103d6bc00cfbfa8cfc9a2599ab518c55643da3f"
+
+bootstrap-switch@~3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/bootstrap-switch/-/bootstrap-switch-3.3.4.tgz#70e0aeb2a877c0dc766991de108e2170fc29a2ff"
+
+bootstrap-touchspin@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/bootstrap-touchspin/-/bootstrap-touchspin-3.1.1.tgz#9779deac72aaf577e5e762b8512c747c871d9597"
+
+bootstrap@3.3.x, bootstrap@^3.3, bootstrap@~3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71"
+
+c3@~0.4.11:
+ version "0.4.23"
+ resolved "https://registry.yarnpkg.com/c3/-/c3-0.4.23.tgz#32ece135d0ac6d124187be5c6935903699643002"
+ dependencies:
+ d3 "~3.5.0"
+
+clipboard@1.7.1:
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-1.7.1.tgz#360d6d6946e99a7a1fef395e42ba92b5e9b5a16b"
+ dependencies:
+ good-listener "^1.2.2"
+ select "^1.1.2"
+ tiny-emitter "^2.0.0"
+
+codemirror@5.33.0:
+ version "5.33.0"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.33.0.tgz#462ad9a6fe8d38b541a9536a3997e1ef93b40c6a"
+
+commander@^2.9.0:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+
+config-chain@~1.1.5:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
+ dependencies:
+ ini "^1.3.4"
+ proto-list "~1.2.1"
+
+cubism@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/cubism/-/cubism-1.6.0.tgz#a566e10594ac59abfc73b829bdee32d91a2f0350"
+ dependencies:
+ d3 "3.x"
+
+d3@3.x, d3@~3.5.0, d3@~3.5.17:
+ version "3.5.17"
+ resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8"
+
+dagre-layout@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/dagre-layout/-/dagre-layout-0.8.0.tgz#7147b6afb655602f855158dfea171db9aa98d4ff"
+ dependencies:
+ graphlib "^2.1.1"
+ lodash "^4.17.4"
+
+datatables.net-bs@>=1.10.9:
+ version "1.10.19"
+ resolved "https://registry.yarnpkg.com/datatables.net-bs/-/datatables.net-bs-1.10.19.tgz#08763b4e4d0cef1a427d019dc15e717c7ed67a4d"
+ dependencies:
+ datatables.net "1.10.19"
+ jquery ">=1.7"
+
+datatables.net-colreorder-bs@~1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/datatables.net-colreorder-bs/-/datatables.net-colreorder-bs-1.3.3.tgz#3a9dcb08deebeb5d854079591e06e493ad793a53"
+ dependencies:
+ datatables.net-bs ">=1.10.9"
+ datatables.net-colreorder ">=1.2.0"
+ jquery ">=1.7"
+
+datatables.net-colreorder@>=1.2.0, datatables.net-colreorder@^1.4.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/datatables.net-colreorder/-/datatables.net-colreorder-1.5.1.tgz#ee5eacd7178b5fd9396aab44d4907aae35086f8c"
+ dependencies:
+ datatables.net "^1.10.15"
+ jquery ">=1.7"
+
+datatables.net-dt@^1.10.11:
+ version "1.10.19"
+ resolved "https://registry.yarnpkg.com/datatables.net-dt/-/datatables.net-dt-1.10.19.tgz#fc668e4942ac6e331be2707975d0f33e01afb60f"
+ dependencies:
+ datatables.net "1.10.19"
+ jquery ">=1.7"
+
+datatables.net-select@~1.2.0:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/datatables.net-select/-/datatables.net-select-1.2.7.tgz#7d5badfca49c438f8b51df04483d8d77857e917c"
+ dependencies:
+ datatables.net "^1.10.15"
+ jquery ">=1.7"
+
+datatables.net@1.10.19, datatables.net@^1.10.11, datatables.net@^1.10.12, datatables.net@^1.10.15:
+ version "1.10.19"
+ resolved "https://registry.yarnpkg.com/datatables.net/-/datatables.net-1.10.19.tgz#97a1ed41c85e62d61040603481b59790a172dd1f"
+ dependencies:
+ jquery ">=1.7"
+
+delegate@^3.1.2:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
+
+drmonty-datatables-colvis@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/drmonty-datatables-colvis/-/drmonty-datatables-colvis-1.1.2.tgz#96ab9edfb48643cc2edda3f87b88933cdee8127c"
+ dependencies:
+ jquery ">=1.7.0"
+
+editorconfig@^0.13.2:
+ version "0.13.3"
+ resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.13.3.tgz#e5219e587951d60958fd94ea9a9a008cdeff1b34"
+ dependencies:
+ bluebird "^3.0.5"
+ commander "^2.9.0"
+ lru-cache "^3.2.0"
+ semver "^5.1.0"
+ sigmund "^1.0.1"
+
+eonasdan-bootstrap-datetimepicker@^4.17.47:
+ version "4.17.47"
+ resolved "https://registry.yarnpkg.com/eonasdan-bootstrap-datetimepicker/-/eonasdan-bootstrap-datetimepicker-4.17.47.tgz#7a49970044065276e7965efd16f822735219e735"
+ dependencies:
+ bootstrap "^3.3"
+ jquery "^1.8.3 || ^2.0 || ^3.0"
+ moment "^2.10"
+ moment-timezone "^0.4.0"
+
+font-awesome-sass@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/font-awesome-sass/-/font-awesome-sass-4.7.0.tgz#4eda693e915009ce00b228e0964dc5eca9bc34e1"
+
+font-awesome@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
+
+good-listener@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+ dependencies:
+ delegate "^3.1.2"
+
+google-code-prettify@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/google-code-prettify/-/google-code-prettify-1.0.5.tgz#9f477f224dbfa62372e5ef803a7e157410400084"
+
+graphlib@^2.1.1:
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.7.tgz#b6a69f9f44bd9de3963ce6804a2fc9e73d86aecc"
+ dependencies:
+ lodash "^4.17.5"
+
+gulp-rename@~1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.2.3.tgz#37b75298e9d3e6c0fe9ac4eac13ce3be5434646b"
+
+ini@^1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+
+jolokia.js@^1.6.0-1:
+ version "1.6.0-1"
+ resolved "https://registry.yarnpkg.com/jolokia.js/-/jolokia.js-1.6.0-1.tgz#b0b527135e16940c2cfbc6b5b50be608177cc50e"
+ dependencies:
+ "@types/jquery" "~2.0.46"
+
+jquery-match-height@^0.7.2:
+ version "0.7.2"
+ resolved "https://registry.yarnpkg.com/jquery-match-height/-/jquery-match-height-0.7.2.tgz#f8d9f3ba5314daab109cf07408674be204be5f0e"
+
+jquery-ui-dist@~1.12.1:
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/jquery-ui-dist/-/jquery-ui-dist-1.12.1.tgz#5c0815d3cc6f90ff5faaf5b268a6e23b4ca904fa"
+
+jquery@2.2.4, "jquery@>= 2.1.x", jquery@>=1.11.0, jquery@>=1.7, jquery@>=1.7.0, "jquery@>=1.7.1 <4.0.0", jquery@>=1.8, "jquery@^1.8.3 || ^2.0 || ^3.0", jquery@~3.2.1:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.4.tgz#2c89d6889b5eac522a7eea32c14521559c6cbf02"
+
+js-beautify@1.7.5:
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.7.5.tgz#69d9651ef60dbb649f65527b53674950138a7919"
+ dependencies:
+ config-chain "~1.1.5"
+ editorconfig "^0.13.2"
+ mkdirp "~0.5.0"
+ nopt "~3.0.1"
+
+js-logger@1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/js-logger/-/js-logger-1.4.1.tgz#f0230dc5e84e120f213d6e5a6b767a913d290335"
+
+keycloak-js@3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-3.4.3.tgz#9fbb1ba7b2433229f5cc8babbd308ff0e945dac7"
+
+lodash@4.x, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.0:
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
+
+lru-cache@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee"
+ dependencies:
+ pseudomap "^1.0.1"
+
+marked@0.3.9:
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.9.tgz#54ce6a57e720c3ac6098374ec625fcbcc97ff290"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+mkdirp@~0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ dependencies:
+ minimist "0.0.8"
+
+moment-timezone@^0.4.0, moment-timezone@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.4.1.tgz#81f598c3ad5e22cdad796b67ecd8d88d0f5baa06"
+ dependencies:
+ moment ">= 2.6.0"
+
+moment@2.21.0, "moment@>= 2.6.0", moment@^2.10, moment@^2.19.1, moment@~2.19.3:
+ version "2.21.0"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a"
+
+ng-idle@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/ng-idle/-/ng-idle-1.3.2.tgz#73a4dcc0a6c8360310d1396df376be6bd0b0a867"
+ dependencies:
+ angular "^1.2.0"
+
+ng-infinite-scroll@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/ng-infinite-scroll/-/ng-infinite-scroll-1.3.0.tgz#c2e98d8fd134b0525a4d2cf58c95d9b583755112"
+
+nopt@~3.0.1:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
+ dependencies:
+ abbrev "1"
+
+patternfly-bootstrap-combobox@~1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/patternfly-bootstrap-combobox/-/patternfly-bootstrap-combobox-1.1.7.tgz#6a5e3ccd1170c21b3c4b4aa168a7413e1ddbb6e1"
+
+patternfly-bootstrap-treeview@~2.1.0:
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/patternfly-bootstrap-treeview/-/patternfly-bootstrap-treeview-2.1.7.tgz#3e325d4ca34040c24e7e3f701c8021b1700a6f5d"
+ dependencies:
+ bootstrap "3.3.x"
+ jquery ">= 2.1.x"
+
+patternfly@^3.37.1:
+ version "3.58.0"
+ resolved "https://registry.yarnpkg.com/patternfly/-/patternfly-3.58.0.tgz#c94516a9fbf2b645b63a53e58fcf39c45bf66a8b"
+ dependencies:
+ bootstrap "~3.3.7"
+ font-awesome "^4.7.0"
+ jquery "~3.2.1"
+ optionalDependencies:
+ "@types/c3" "^0.6.0"
+ bootstrap-datepicker "^1.7.1"
+ bootstrap-sass "^3.3.7"
+ bootstrap-select "1.12.2"
+ bootstrap-slider "^9.9.0"
+ bootstrap-switch "~3.3.4"
+ bootstrap-touchspin "~3.1.1"
+ c3 "~0.4.11"
+ d3 "~3.5.17"
+ datatables.net "^1.10.15"
+ datatables.net-colreorder "^1.4.1"
+ datatables.net-colreorder-bs "~1.3.2"
+ datatables.net-select "~1.2.0"
+ drmonty-datatables-colvis "~1.1.2"
+ eonasdan-bootstrap-datetimepicker "^4.17.47"
+ font-awesome-sass "^4.7.0"
+ google-code-prettify "~1.0.5"
+ jquery-match-height "^0.7.2"
+ moment "^2.19.1"
+ moment-timezone "^0.4.1"
+ patternfly-bootstrap-combobox "~1.1.7"
+ patternfly-bootstrap-treeview "~2.1.0"
+
+proto-list@~1.2.1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
+
+pseudomap@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+
+select@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+
+semver@^5.1.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+
+sigmund@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
+
+tiny-emitter@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"
+
+urijs@1.19.0:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.0.tgz#d8aa284d0e7469703a6988ad045c4cbfdf08ada0"
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/gulpfile.js" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/gulpfile.js"
new file mode 100755
index 0000000..5ae017e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/gulpfile.js"
@@ -0,0 +1,294 @@
+const gulp = require('gulp');
+const eventStream = require('event-stream');
+const gulpLoadPlugins = require('gulp-load-plugins');
+const map = require('vinyl-map');
+const fs = require('fs');
+const path = require('path');
+const sequence = require('run-sequence');
+const size = require('gulp-size');
+const uri = require('urijs');
+const s = require('underscore.string');
+const argv = require('yargs').argv;
+const logger = require('js-logger');
+const hawtio = require('@hawtio/node-backend');
+const tslint = require('gulp-tslint');
+const tslintRules = require('./tslint.json');
+const exec = require('child_process').exec;
+const usemin = require('gulp-usemin');
+const uglify = require('gulp-uglify');
+const cleanCss = require('gulp-clean-css');
+const rev = require('gulp-rev');
+const preprocess = require("gulp-preprocess");
+
+const plugins = gulpLoadPlugins({});
+
+const config = {
+ proxyPort: argv.port || 8181,
+ targetPath: argv.path || '/hawtio/jolokia',
+ logLevel: argv.debug ? logger.DEBUG : logger.INFO,
+ keycloak: argv.keycloak ? 'true' : 'false',
+ app: 'app/',
+ src: 'app/src/',
+ srcLess: 'app/src/**/*.less',
+ srcTemplates: 'app/src/**/!(index|login).html',
+ docTemplates: '../@(CHANGES|FAQ).md',
+ templateModule: 'hawtio-console-assembly-templates',
+ temp: 'temp/',
+ dist: 'dist/',
+ distFonts: 'dist/fonts',
+ distImg: 'dist/img',
+ js: 'hawtio-console-assembly.js',
+ css: 'hawtio-console-assembly.css',
+ tsProject: plugins.typescript.createProject('tsconfig.json'),
+ tsLintOptions: {
+ rulesDirectory: './tslint-rules/'
+ },
+ sourceMap: argv.sourcemap
+};
+
+var normalSizeOptions = {
+ showFiles: true
+}, gZippedSizeOptions = {
+ showFiles: true,
+ gzip: true
+};
+
+//------------------------------------------------------------------------------
+// build tasks
+//------------------------------------------------------------------------------
+
+gulp.task('clean', function () {
+ return gulp.src(['dist', 'temp'], { read: false })
+ .pipe(plugins.clean());
+});
+
+gulp.task('tsc', function () {
+ return config.tsProject.src()
+ .pipe(plugins.debug({ title: 'tsc' }))
+ .pipe(plugins.if(config.sourceMap, plugins.sourcemaps.init()))
+ .pipe(config.tsProject())
+ .js
+ .pipe(plugins.ngAnnotate())
+ .pipe(plugins.debug({ title: 'tsc js' }))
+ .pipe(plugins.if(config.sourceMap, plugins.sourcemaps.write()))
+ .pipe(gulp.dest(config.temp));
+});
+
+gulp.task('template', function () {
+ return gulp.src(config.srcTemplates)
+ .pipe(plugins.debug({ title: 'template' }))
+ .pipe(plugins.angularTemplatecache({
+ filename: 'templates.js',
+ root: config.src,
+ standalone: true,
+ module: config.templateModule,
+ templateFooter: '}]); hawtioPluginLoader.addModule("' + config.templateModule + '");'
+ }))
+ .pipe(gulp.dest(config.temp));
+});
+
+gulp.task('template-docs', function () {
+ return gulp.src(config.docTemplates)
+ .pipe(plugins.angularTemplatecache({
+ filename: 'doc-templates.js',
+ root: 'plugins/help/doc',
+ standalone: true,
+ module: config.templateModule,
+ templateFooter: '}]); hawtioPluginLoader.addModule("' + config.templateModule + '");'
+ }))
+ .pipe(gulp.dest(config.temp));
+});
+
+gulp.task('concat', function () {
+ var gZipSize = size(gZippedSizeOptions);
+ var license = tslintRules.rules['license-header'][1];
+ return gulp.src(config.temp + '*.js')
+ .pipe(plugins.concat(config.js))
+ .pipe(plugins.header(license))
+ .pipe(size(normalSizeOptions))
+ .pipe(gZipSize)
+ .pipe(gulp.dest(config.temp));
+});
+
+gulp.task('less', function () {
+ return gulp.src(config.srcLess)
+ .pipe(plugins.less())
+ .pipe(plugins.concat(config.css))
+ .pipe(gulp.dest(config.temp));
+});
+
+gulp.task('usemin', function () {
+ return gulp.src(config.src + '@(index|login).html')
+ .pipe(preprocess())
+ .pipe(usemin({
+ libCss: [cleanCss, rev],
+ appCss: [() => cleanCss({ rebaseTo: 'css/css' }), rev],
+ libJs: [uglify, rev],
+ appJs: [uglify, rev],
+ jsAttributes: { defer: true }
+ }))
+ .pipe(plugins.debug({ title: 'usemin' }))
+ .pipe(gulp.dest(config.dist));
+});
+
+gulp.task('install-dependencies', function (cb) {
+ exec(`cd ${config.app} && yarn install --prod --flat --frozen-lockfile && cd ..`, function (error, stdout, stderr) {
+ if (error) {
+ console.log(stderr);
+ }
+ cb(error);
+ });
+});
+
+gulp.task('copy-fonts', function () {
+ return gulp.src('app/node_modules/patternfly/dist/fonts/*')
+ .pipe(plugins.debug({ title: 'copy-fonts' }))
+ .pipe(gulp.dest(config.distFonts));
+});
+
+gulp.task('copy-images', function () {
+ var hawtioDependencies = config.app + 'node_modules/@hawtio';
+ var dirs = fs.readdirSync(hawtioDependencies);
+ var patterns = [];
+ dirs.forEach(function (dir) {
+ var path = hawtioDependencies + '/' + dir + '/dist/img';
+ try {
+ if (fs.statSync(path).isDirectory()) {
+ console.log('found image dir: ', path);
+ var pattern = hawtioDependencies + '/' + dir + '/dist/img/**/*';
+ patterns.push(pattern);
+ }
+ } catch (e) {
+ // ignore, file does not exist
+ }
+ });
+ // Add PatternFly images package in dist
+ patterns.push(config.app + 'node_modules/patternfly/dist/img/**/*');
+ return gulp.src(patterns)
+ .pipe(plugins.debug({ title: 'copy-images' }))
+ .pipe(gulp.dest(config.distImg));
+});
+
+gulp.task('404', function () {
+ return gulp.src(config.dist + 'index.html')
+ .pipe(plugins.rename('404.html'))
+ .pipe(gulp.dest(config.dist));
+});
+
+gulp.task('copy-config', function () {
+ return gulp.src(config.src + '*.json')
+ .pipe(gulp.dest(config.dist));
+});
+
+//------------------------------------------------------------------------------
+// serve tasks
+//------------------------------------------------------------------------------
+
+gulp.task('connect', function () {
+ hawtio.setConfig({
+ logLevel: config.logLevel,
+ port: 2772,
+ proxy: '/hawtio/proxy',
+ staticProxies: [
+ {
+ proto: 'http',
+ port: config.proxyPort,
+ hostname: 'localhost',
+ path: '/hawtio/jolokia',
+ targetPath: config.targetPath
+ }
+ ],
+ staticAssets: [{
+ path: '/hawtio/',
+ dir: './dist/'
+ }],
+ fallback: './dist/index.html',
+ liveReload: {
+ enabled: true
+ }
+ });
+
+ hawtio.use('/', (req, res, next) => {
+ if (!s.startsWith(req.originalUrl, '/hawtio/')
+ || s.startsWith(req.originalUrl, '/hawtio/jvm/')
+ || s.startsWith(req.originalUrl, '/hawtio/help')
+ || s.startsWith(req.originalUrl, '/hawtio/preferences')) {
+ res.redirect('/hawtio/');
+ } else {
+ next();
+ }
+ });
+
+ hawtio.use('/hawtio/refresh', (req, res, next) => {
+ res.set('Content-Type', 'text/html;charset=UTF-8');
+ res.send('ok');
+ });
+
+ // used for hawtio-login
+ hawtio.use('/hawtio/auth/login', (req, res, next) => {
+ // login always succeeds
+ res.set('Content-Type', 'application/json');
+ res.send('{}');
+ });
+
+ // used for hawtio-login
+ hawtio.use('/hawtio/auth/logout', (req, res, next) => {
+ res.redirect('/hawtio/login.html');
+ });
+
+ // used for hawtio-login
+ hawtio.use('/hawtio/user', (req, res, next) => {
+ // login always succeeds
+ res.set('Content-Type', 'application/json');
+ res.send('"public"');
+ });
+
+ // used for hawtio-login
+ hawtio.use('/hawtio/keycloak/enabled', (req, res, next) => {
+ res.set('Content-Type', 'application/json');
+ res.send(config.keycloak);
+ });
+
+ // used for hawtio-login
+ hawtio.use('/hawtio/keycloak/client-config', (req, res, next) => {
+ res.set('Content-Type', 'application/json');
+ res.send(`
+ {
+ "clientId": "hawtio-client",
+ "url": "http://localhost:18080/auth",
+ "realm": "hawtio-demo"
+ }
+ `);
+ });
+
+ // used for hawtio-login
+ hawtio.use('/hawtio/keycloak/validate-subject-matches', (req, res, next) => {
+ res.set('Content-Type', 'application/json');
+ res.send('true');
+ });
+
+ hawtio.listen(function (server) {
+ var host = server.address().address;
+ var port = server.address().port;
+ console.log("started from gulp file at", host, ":", port);
+ });
+});
+
+gulp.task('watch', function () {
+ gulp.watch(config.src + '**/*', ['build']);
+ gulp.watch(config.dist + '*', ['reload']);
+});
+
+gulp.task('reload', function () {
+ gulp.src('dist/@(index|login).html')
+ .pipe(hawtio.reload());
+});
+
+//------------------------------------------------------------------------------
+// main tasks
+//------------------------------------------------------------------------------
+
+gulp.task('build', callback => sequence('clean', 'tsc', 'template', 'template-docs', 'concat', 'less',
+ 'install-dependencies', 'usemin', 'copy-fonts', 'copy-images', '404', 'copy-config', callback));
+
+gulp.task('default', callback => sequence('build', ['connect', 'watch']));
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/package.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/package.json"
new file mode 100755
index 0000000..a7553da
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/package.json"
@@ -0,0 +1,51 @@
+{
+ "name": "@hawtio/console-assembly",
+ "version": "2.0.0",
+ "description": "The hawt.io web console helps you manage your JVM stuff and stay cool!",
+ "scripts": {
+ "postinstall": "cd app && yarn install --prod --flat",
+ "start": "gulp",
+ "build": "gulp build"
+ },
+ "devDependencies": {
+ "@hawtio/node-backend": "^3.0.0",
+ "event-stream": "3.3.4",
+ "gulp": "^3.0.0",
+ "gulp-angular-templatecache": "^2.0.0",
+ "gulp-chmod": "^2.0.0",
+ "gulp-clean": "~0.3.0",
+ "gulp-clean-css": "^4.0.0",
+ "gulp-concat": "^2.0.0",
+ "gulp-debug": "^3.1.0",
+ "gulp-dedupe": "0.0.2",
+ "gulp-flatten": "~0.3.0",
+ "gulp-gh-pages": "~0.5.0",
+ "gulp-header": "^1.0.0",
+ "gulp-if": "^2.0.2",
+ "gulp-less": "^3.0.0",
+ "gulp-load-plugins": "^1.0.0",
+ "gulp-ng-annotate": "~2.0.0",
+ "gulp-preprocess": "~3.0.1",
+ "gulp-rename": "^1.0.0",
+ "gulp-replace": "^0.6.1",
+ "gulp-rev": "^9.0.0",
+ "gulp-size": "^2.0.0",
+ "gulp-sourcemaps": "^2.6.0",
+ "gulp-tslint": "^8.1.1",
+ "gulp-typescript": "^4.0.0",
+ "gulp-uglify": "^3.0.0",
+ "gulp-usemin": "~0.3.0",
+ "run-sequence": "^2.0.0",
+ "tslint": "^5.4.3",
+ "typescript": "^3.0.0",
+ "underscore.string": "^3.0.0",
+ "urijs": "^1.0.0",
+ "url-join": "^2.0.2",
+ "vinyl-map": "^1.0.0"
+ },
+ "license": "Apache-2.0",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/hawtio/hawtio.git"
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/pom.xml"
new file mode 100755
index 0000000..a177d90
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/pom.xml"
@@ -0,0 +1,107 @@
+
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-console-assembly
+ ${project.artifactId}
+ hawtio :: ${project.artifactId}
+
+
+
+
+
+
+
+
+ com.github.eirslett
+ frontend-maven-plugin
+ ${frontend-maven-plugin-version}
+
+
+ install node and npm
+
+ install-node-and-npm
+
+
+ v8.11.3
+ 5.6.0
+
+
+
+ install node and yarn
+
+ install-node-and-yarn
+
+
+ v8.11.3
+ v1.9.4
+
+
+
+ yarn install
+
+ yarn
+
+
+ install
+
+
+
+ yarn run build
+
+ yarn
+
+
+ run build
+
+
+
+
+
+
+ maven-clean-plugin
+
+
+
+
+ ${basedir}/dist
+
+ **/*
+
+ false
+
+
+ ${basedir}/node_modules
+
+ **/*
+
+ false
+
+
+ ${basedir}/app/node_modules
+
+ **/*
+
+ false
+
+
+ ${basedir}/temp
+
+ **/*
+
+ false
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tsconfig.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tsconfig.json"
new file mode 100755
index 0000000..4c05019
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tsconfig.json"
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "ES5",
+ "declaration": false,
+ "outFile": "compiled.js",
+ "typeRoots": [
+ "app/node_modules/@types",
+ "app/node_modules/@hawtio"
+ ]
+ },
+ "include": [
+ "app/src/**/*.ts",
+ "app/node_modules/jolokia.js/index.d.ts"
+ ]
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tslint-rules/licenseHeaderRule.js" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tslint-rules/licenseHeaderRule.js"
new file mode 100755
index 0000000..0e18d33
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tslint-rules/licenseHeaderRule.js"
@@ -0,0 +1,28 @@
+function Rule() {
+ Lint.Rules.AbstractRule.apply(this, arguments);
+}
+
+Rule.prototype = Object.create(Lint.Rules.AbstractRule.prototype);
+Rule.prototype.apply = function(sourceFile) {
+ return this.applyWithWalker(new LicenseHeaderWalker(sourceFile, this.getOptions()));
+};
+
+function LicenseHeaderWalker() {
+ Lint.RuleWalker.apply(this, arguments);
+}
+
+LicenseHeaderWalker.prototype = Object.create(Lint.RuleWalker.prototype);
+LicenseHeaderWalker.prototype.visitSourceFile = function (node) {
+ // create a failure at the current position
+ var sourceText = this.getSourceFile().text;
+
+ var licenceHeader = this.getOptions()[0];
+
+ if ( sourceText.indexOf(licenceHeader) !== 0 ){
+ this.addFailure(this.createFailure(0, 0, "Missing or incorrect project license header."));
+ }
+
+ Lint.RuleWalker.prototype.visitSourceFile.call(this, node);
+};
+
+exports.Rule = Rule;
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tslint.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tslint.json"
new file mode 100755
index 0000000..0150dad
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/tslint.json"
@@ -0,0 +1,48 @@
+{
+ "rules": {
+ "class-name": true,
+ "curly": true,
+ "eofline": true,
+ "forin": true,
+ "indent": [true, "spaces"],
+ "label-position": true,
+ "label-undefined": true,
+ "no-arg": true,
+ "no-bitwise": true,
+ "no-console": [true,
+ "trace"
+ ],
+ "no-construct": true,
+ "no-debugger": false,
+ "no-duplicate-key": true,
+ "no-duplicate-variable": true,
+ "no-empty": true,
+ "no-eval": true,
+ "no-string-literal": false,
+ "no-switch-case-fall-through": true,
+ "no-trailing-comma": true,
+ "no-unused-expression": true,
+ "no-unused-variable": false,
+ "no-unreachable": true,
+ "no-use-before-declare": true,
+ "one-line": [true,
+ "check-open-brace",
+ "check-catch",
+ "check-else",
+ "check-whitespace"
+ ],
+ "radix": true,
+ "semicolon": true,
+ "triple-equals": [true, "allow-null-check"],
+ "variable-name": false,
+ "whitespace": [false,
+ "check-branch",
+ "check-decl",
+ "check-operator",
+ "check-separator"
+ ],
+ "license-header": [ true,
+ "/// Copyright 2014-2015 Red Hat, Inc. and/or its affiliates\n/// and other contributors as indicated by the @author tags.\n///\n/// Licensed under the Apache License, Version 2.0 (the \"License\");\n/// you may not use this file except in compliance with the License.\n/// You may obtain a copy of the License at\n///\n/// http://www.apache.org/licenses/LICENSE-2.0\n///\n/// Unless required by applicable law or agreed to in writing, software\n/// distributed under the License is distributed on an \"AS IS\" BASIS,\n/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n/// See the License for the specific language governing permissions and\n/// limitations under the License.\n"
+ ]
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/yarn.lock" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/yarn.lock"
new file mode 100755
index 0000000..7cd06c5
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-console-assembly/yarn.lock"
@@ -0,0 +1,4811 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@gulp-sourcemaps/identity-map@1.X":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9"
+ integrity sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==
+ dependencies:
+ acorn "^5.0.3"
+ css "^2.2.1"
+ normalize-path "^2.1.1"
+ source-map "^0.6.0"
+ through2 "^2.0.3"
+
+"@gulp-sourcemaps/map-sources@1.X":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda"
+ integrity sha1-iQrnxdjId/bThIYCFazp1+yUW9o=
+ dependencies:
+ normalize-path "^2.0.1"
+ through2 "^2.0.3"
+
+"@hawtio/node-backend@^3.0.0":
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/@hawtio/node-backend/-/node-backend-3.1.5.tgz#320aae8ecb0ff42ab48fa9677e9a0e204b827cf5"
+ integrity sha512-PBbxPSx8BTistX2MmKPmtH4bTkNG0Qd+AEwkcG+0HTwlAtfzFGUfOwVtOReDF/H8cN4ag0SN6bp+c0Q+9Kk6CA==
+ dependencies:
+ "@types/node" "^7.0.31"
+ body-parser "^1.17.2"
+ connect-livereload "^0.6.0"
+ event-stream "3.3.4"
+ express "^4.15.3"
+ express-ws "^3.0.0"
+ http-proxy "^1.16.2"
+ js-logger "^1.3.0"
+ lodash "^4.17.4"
+ request "^2.81.0"
+ tiny-lr "^1.0.5"
+ underscore.string "^3.3.4"
+ urijs "^1.18.10"
+
+"@types/fancy-log@1.3.0":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.0.tgz#a61ab476e5e628cd07a846330df53b85e05c8ce0"
+ integrity sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==
+
+"@types/node@^7.0.31":
+ version "7.10.2"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-7.10.2.tgz#a98845168012d7a63a84d50e738829da43bdb0de"
+ integrity sha512-RO4ig5taKmcrU4Rex8ojG1gpwFkjddzug9iPQSDvbewHN9vDpcFewevkaOK+KT+w1LeZnxbgOyfXwV4pxsQ4GQ==
+
+accepts@~1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
+ integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I=
+ dependencies:
+ mime-types "~2.1.18"
+ negotiator "0.6.1"
+
+accord@^0.28.0:
+ version "0.28.0"
+ resolved "https://registry.yarnpkg.com/accord/-/accord-0.28.0.tgz#bec516a2f722e7d50f5f9f42f81b77f3b95448ba"
+ integrity sha512-sPF34gqHegaCSryKf5wHJ8wREK1dTZnHmC9hsB7D8xjntRdd30DXDPKf0YVIcSvnXJmcYu5SCvZRz28H++kFhQ==
+ dependencies:
+ convert-source-map "^1.5.0"
+ glob "^7.0.5"
+ indx "^0.2.3"
+ lodash.clone "^4.3.2"
+ lodash.defaults "^4.0.1"
+ lodash.flatten "^4.2.0"
+ lodash.merge "^4.4.0"
+ lodash.partialright "^4.1.4"
+ lodash.pick "^4.2.1"
+ lodash.uniq "^4.3.0"
+ resolve "^1.5.0"
+ semver "^5.3.0"
+ uglify-js "^2.8.22"
+ when "^3.7.8"
+
+acorn@5.X, acorn@^5.0.3:
+ version "5.7.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+ integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+
+acorn@~2.6.4:
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.6.4.tgz#eb1f45b4a43fa31d03701a5ec46f3b52673e90ee"
+ integrity sha1-6x9FtKQ/ox0DcBpexG87Umc+kO4=
+
+ajv@^4.9.1:
+ version "4.11.8"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
+ integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=
+ dependencies:
+ co "^4.6.0"
+ json-stable-stringify "^1.0.1"
+
+ajv@^6.5.5:
+ version "6.5.5"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.5.tgz#cf97cdade71c6399a92c6d6c4177381291b781a1"
+ integrity sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==
+ dependencies:
+ fast-deep-equal "^2.0.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+align-text@^0.1.1, align-text@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+ integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
+ dependencies:
+ kind-of "^3.0.2"
+ longest "^1.0.1"
+ repeat-string "^1.5.2"
+
+alter@~0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd"
+ integrity sha1-x1iICGF1cgNKrmJICvJrHU0cs80=
+ dependencies:
+ stable "~0.1.3"
+
+ansi-colors@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
+ integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==
+ dependencies:
+ ansi-wrap "^0.1.0"
+
+ansi-cyan@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873"
+ integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=
+ dependencies:
+ ansi-wrap "0.1.0"
+
+ansi-gray@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251"
+ integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE=
+ dependencies:
+ ansi-wrap "0.1.0"
+
+ansi-red@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c"
+ integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=
+ dependencies:
+ ansi-wrap "0.1.0"
+
+ansi-regex@^0.2.0, ansi-regex@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9"
+ integrity sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-styles@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de"
+ integrity sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-wrap@0.1.0, ansi-wrap@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf"
+ integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768=
+
+append-buffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1"
+ integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=
+ dependencies:
+ buffer-equal "^1.0.0"
+
+archy@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
+ integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+arr-diff@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a"
+ integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo=
+ dependencies:
+ arr-flatten "^1.0.1"
+ array-slice "^0.2.3"
+
+arr-diff@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+ integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
+ dependencies:
+ arr-flatten "^1.0.1"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+ integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-flatten@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+ integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^2.0.1:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d"
+ integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+ integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-differ@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
+ integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
+
+array-each@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
+ integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8=
+
+array-find-index@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+ integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
+array-slice@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
+ integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU=
+
+array-slice@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
+ integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
+
+array-uniq@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+ integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
+
+array-unique@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+ integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
+
+asap@~2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+ integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
+
+asn1@~0.2.3:
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+ integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+ dependencies:
+ safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+ integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+
+assert-plus@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+ integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ=
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+ integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+
+atob@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+aws-sign2@~0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+ integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8=
+
+aws-sign2@~0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+ integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+
+aws4@^1.2.1, aws4@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
+ integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+
+babel-code-frame@^6.22.0:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
+ integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
+ dependencies:
+ chalk "^1.1.3"
+ esutils "^2.0.2"
+ js-tokens "^3.0.2"
+
+balanced-match@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+ integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+bcrypt-pbkdf@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+ integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+ dependencies:
+ tweetnacl "^0.14.3"
+
+beeper@^1.0.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
+ integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=
+
+binaryextensions@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-1.0.1.tgz#1e637488b35b58bda5f4774bf96a5212a8c90755"
+ integrity sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U=
+
+bl@^1.1.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e"
+ integrity sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=
+ dependencies:
+ readable-stream "^2.0.5"
+
+body-parser@1.18.3, body-parser@^1.17.2:
+ version "1.18.3"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
+ integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
+ dependencies:
+ bytes "3.0.0"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "~1.1.2"
+ http-errors "~1.6.3"
+ iconv-lite "0.4.23"
+ on-finished "~2.3.0"
+ qs "6.5.2"
+ raw-body "2.3.3"
+ type-is "~1.6.16"
+
+body@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069"
+ integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=
+ dependencies:
+ continuable-cache "^0.3.1"
+ error "^7.0.0"
+ raw-body "~1.1.0"
+ safe-json-parse "~1.0.1"
+
+boom@2.x.x:
+ version "2.10.1"
+ resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+ integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=
+ dependencies:
+ hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
+ integrity sha1-wHshHHyVLsH479Uad+8NHTmQopI=
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+braces@^1.8.2:
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+ integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
+ dependencies:
+ expand-range "^1.8.1"
+ preserve "^0.2.0"
+ repeat-element "^1.1.2"
+
+buffer-equal@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe"
+ integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74=
+
+bufferstreams@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/bufferstreams/-/bufferstreams-1.1.3.tgz#a8515ac024fa90e8fa7d58c11b13dea1f28abe72"
+ integrity sha512-HaJnVuslRF4g2kSDeyl++AaVizoitCpL9PglzCYwy0uHHyvWerfvEb8jWmYbF1z4kiVFolGomnxSGl+GUQp2jg==
+ dependencies:
+ readable-stream "^2.0.2"
+
+builtin-modules@^1.0.0, builtin-modules@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+ integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
+
+bytes@1:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8"
+ integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=
+
+bytes@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+ integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+camelcase-keys@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+ integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+ dependencies:
+ camelcase "^2.0.0"
+ map-obj "^1.0.0"
+
+camelcase@^1.0.2:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+ integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
+
+camelcase@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+ integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
+
+caseless@~0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+ integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+
+center-align@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+ integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
+ dependencies:
+ align-text "^0.1.3"
+ lazy-cache "^1.0.3"
+
+chalk@2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
+ integrity sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==
+ dependencies:
+ ansi-styles "^3.2.0"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.2.0"
+
+chalk@^0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174"
+ integrity sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=
+ dependencies:
+ ansi-styles "^1.1.0"
+ escape-string-regexp "^1.0.0"
+ has-ansi "^0.1.0"
+ strip-ansi "^0.3.0"
+ supports-color "^0.2.0"
+
+chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.3.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
+ integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+clean-css@4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
+ integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+ dependencies:
+ source-map "~0.6.0"
+
+cliui@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+ integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
+ dependencies:
+ center-align "^0.1.1"
+ right-align "^0.1.1"
+ wordwrap "0.0.2"
+
+clone-buffer@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
+ integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
+
+clone-stats@^0.0.1, clone-stats@~0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+ integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=
+
+clone-stats@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
+ integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
+
+clone@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f"
+ integrity sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=
+
+clone@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+ integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
+
+clone@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f"
+ integrity sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=
+
+clone@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+ integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
+
+cloneable-readable@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65"
+ integrity sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==
+ dependencies:
+ inherits "^2.0.1"
+ process-nextick-args "^2.0.0"
+ readable-stream "^2.3.5"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-support@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
+ integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
+
+colors@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
+ integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
+
+combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
+ integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@^2.12.1:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+ integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
+
+commander@~2.17.1:
+ version "2.17.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+ integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-with-sourcemaps@*, concat-with-sourcemaps@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e"
+ integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==
+ dependencies:
+ source-map "^0.6.1"
+
+connect-livereload@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/connect-livereload/-/connect-livereload-0.6.0.tgz#f9f009874ad6837183afb170b4c4e3857a1d7ceb"
+ integrity sha1-+fAJh0rWg3GDr7FwtMTjhXodfOs=
+
+content-disposition@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
+ integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
+
+content-type@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+ integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
+continuable-cache@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f"
+ integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=
+
+convert-source-map@1.X, convert-source-map@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
+ integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
+ dependencies:
+ safe-buffer "~5.1.1"
+
+convert-source-map@^1.1.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
+ integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=
+
+convert-source-map@~1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
+ integrity sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
+ integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
+
+core-util-is@1.0.2, core-util-is@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+cryptiles@2.x.x:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+ integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=
+ dependencies:
+ boom "2.x.x"
+
+css@2.X, css@^2.2.1:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
+ integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==
+ dependencies:
+ inherits "^2.0.3"
+ source-map "^0.6.1"
+ source-map-resolve "^0.5.2"
+ urix "^0.1.0"
+
+currently-unhandled@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+ integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
+ dependencies:
+ array-find-index "^1.0.1"
+
+d@1:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
+ integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=
+ dependencies:
+ es5-ext "^0.10.9"
+
+dashdash@^1.12.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+ integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
+ dependencies:
+ assert-plus "^1.0.0"
+
+dateformat@^1.0.7-1.2.3:
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9"
+ integrity sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=
+ dependencies:
+ get-stdin "^4.0.1"
+ meow "^3.3.0"
+
+dateformat@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062"
+ integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=
+
+debug-fabulous@1.X:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e"
+ integrity sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==
+ dependencies:
+ debug "3.X"
+ memoizee "0.4.X"
+ object-assign "4.X"
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@3.X, debug@^3.1.0:
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+ integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+ dependencies:
+ ms "^2.1.1"
+
+debug@=3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+ dependencies:
+ ms "2.0.0"
+
+decamelize@^1.0.0, decamelize@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decode-uri-component@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+ integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+deep-assign@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b"
+ integrity sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=
+ dependencies:
+ is-obj "^1.0.0"
+
+defaults@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
+ integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
+ dependencies:
+ clone "^1.0.2"
+
+define-properties@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+ integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+ dependencies:
+ object-keys "^1.0.12"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+ integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+deprecated@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19"
+ integrity sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=
+
+destroy@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+ integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+detect-file@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
+ integrity sha1-STXe39lIhkjgBrASlWbpOGcR6mM=
+ dependencies:
+ fs-exists-sync "^0.1.0"
+
+detect-newline@2.X:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
+ integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=
+
+diff@^3.2.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
+ integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+
+diff@~1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-1.0.8.tgz#343276308ec991b7bc82267ed55bc1411f971666"
+ integrity sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=
+
+duplexer2@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
+ integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=
+ dependencies:
+ readable-stream "~1.1.9"
+
+duplexer@^0.1.1, duplexer@~0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
+ integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=
+
+duplexify@^3.2.0, duplexify@^3.5.0:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd"
+ integrity sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==
+ dependencies:
+ end-of-stream "^1.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+ stream-shift "^1.0.0"
+
+duplexify@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.0.tgz#592903f5d80b38d037220541264d69a198fb3410"
+ integrity sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==
+ dependencies:
+ end-of-stream "^1.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+ stream-shift "^1.0.0"
+
+ecc-jsbn@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+ integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
+ dependencies:
+ jsbn "~0.1.0"
+ safer-buffer "^2.1.0"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+end-of-stream@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
+ integrity sha1-epDYM+/abPpurA9JSduw+tOmMgY=
+ dependencies:
+ once "^1.4.0"
+
+end-of-stream@^1.1.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+ integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
+ dependencies:
+ once "^1.4.0"
+
+end-of-stream@~0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf"
+ integrity sha1-jhdyBsPICDfYVjLouTWd/osvbq8=
+ dependencies:
+ once "~1.3.0"
+
+errno@^0.1.1:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+ integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
+ dependencies:
+ prr "~1.0.1"
+
+error-ex@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+error@^7.0.0:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02"
+ integrity sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=
+ dependencies:
+ string-template "~0.2.1"
+ xtend "~4.0.0"
+
+es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
+ version "0.10.46"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.46.tgz#efd99f67c5a7ec789baa3daa7f79870388f7f572"
+ integrity sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==
+ dependencies:
+ es6-iterator "~2.0.3"
+ es6-symbol "~3.1.1"
+ next-tick "1"
+
+es6-iterator@^2.0.1, es6-iterator@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
+ integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
+ dependencies:
+ d "1"
+ es5-ext "^0.10.35"
+ es6-symbol "^3.1.1"
+
+es6-promise@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-2.3.0.tgz#96edb9f2fdb01995822b263dd8aadab6748181bc"
+ integrity sha1-lu258v2wGZWCKyY92KratnSBgbw=
+
+es6-symbol@^3.1.1, es6-symbol@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
+ integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
+es6-weak-map@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
+ integrity sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=
+ dependencies:
+ d "1"
+ es5-ext "^0.10.14"
+ es6-iterator "^2.0.1"
+ es6-symbol "^3.1.1"
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esutils@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+ integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+event-emitter@^0.3.5:
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+ integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
+ dependencies:
+ d "1"
+ es5-ext "~0.10.14"
+
+event-stream@*:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-4.0.1.tgz#4092808ec995d0dd75ea4580c1df6a74db2cde65"
+ integrity sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==
+ dependencies:
+ duplexer "^0.1.1"
+ from "^0.1.7"
+ map-stream "0.0.7"
+ pause-stream "^0.0.11"
+ split "^1.0.1"
+ stream-combiner "^0.2.2"
+ through "^2.3.8"
+
+event-stream@3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
+ integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=
+ dependencies:
+ duplexer "~0.1.1"
+ from "~0"
+ map-stream "~0.1.0"
+ pause-stream "0.0.11"
+ split "0.3"
+ stream-combiner "~0.0.4"
+ through "~2.3.1"
+
+eventemitter3@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
+ integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==
+
+expand-brackets@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+ integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
+ dependencies:
+ is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+ integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
+ dependencies:
+ fill-range "^2.1.0"
+
+expand-tilde@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
+ integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
+ dependencies:
+ os-homedir "^1.0.1"
+
+expand-tilde@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+ integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
+express-ws@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/express-ws/-/express-ws-3.0.0.tgz#7ddaaf3b7c758865c099905989911b6234477dbd"
+ integrity sha1-fdqvO3x1iGXAmZBZiZEbYjRHfb0=
+ dependencies:
+ ws "^2.0.0"
+
+express@^4.15.3:
+ version "4.16.4"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
+ integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
+ dependencies:
+ accepts "~1.3.5"
+ array-flatten "1.1.1"
+ body-parser "1.18.3"
+ content-disposition "0.5.2"
+ content-type "~1.0.4"
+ cookie "0.3.1"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "~1.1.2"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.1.1"
+ fresh "0.5.2"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "~2.3.0"
+ parseurl "~1.3.2"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.4"
+ qs "6.5.2"
+ range-parser "~1.2.0"
+ safe-buffer "5.1.2"
+ send "0.16.2"
+ serve-static "1.13.2"
+ setprototypeof "1.1.0"
+ statuses "~1.4.0"
+ type-is "~1.6.16"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+extend-shallow@^1.1.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071"
+ integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=
+ dependencies:
+ kind-of "^1.1.0"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
+ integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=
+
+extend@~3.0.0, extend@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+extglob@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+ integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
+ dependencies:
+ is-extglob "^1.0.0"
+
+extsprintf@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+ integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
+
+extsprintf@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+ integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
+
+fancy-log@1.3.2, fancy-log@^1.1.0, fancy-log@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1"
+ integrity sha1-9BEl49hPLn2JpD0G2VjI94vha+E=
+ dependencies:
+ ansi-gray "^0.1.1"
+ color-support "^1.1.3"
+ time-stamp "^1.0.0"
+
+fancy-log@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948"
+ integrity sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=
+ dependencies:
+ chalk "^1.1.1"
+ time-stamp "^1.0.0"
+
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+ integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+ integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+
+faye-websocket@~0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
+ integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=
+ dependencies:
+ websocket-driver ">=0.5.1"
+
+filename-regex@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+ integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=
+
+fill-range@^2.1.0:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+ integrity sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=
+ dependencies:
+ is-number "^2.1.0"
+ isobject "^2.0.0"
+ randomatic "^1.1.3"
+ repeat-element "^1.1.2"
+ repeat-string "^1.5.2"
+
+finalhandler@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
+ integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.2"
+ statuses "~1.4.0"
+ unpipe "~1.0.0"
+
+find-index@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
+ integrity sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=
+
+find-up@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+ integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+ dependencies:
+ path-exists "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+findup-sync@^0.4.0, findup-sync@^0.4.2:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
+ integrity sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=
+ dependencies:
+ detect-file "^0.1.0"
+ is-glob "^2.0.1"
+ micromatch "^2.3.7"
+ resolve-dir "^0.1.0"
+
+fined@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.0.tgz#b37dc844b76a2f5e7081e884f7c0ae344f153476"
+ integrity sha1-s33IRLdqL15wgeiE98CuNE8VNHY=
+ dependencies:
+ expand-tilde "^2.0.2"
+ is-plain-object "^2.0.3"
+ object.defaults "^1.1.0"
+ object.pick "^1.2.0"
+ parse-filepath "^1.0.1"
+
+first-chunk-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
+ integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=
+
+first-chunk-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
+ integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=
+ dependencies:
+ readable-stream "^2.0.2"
+
+flagged-respawn@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
+ integrity sha1-/xke3c1wiKZ1smEP/8l2vpuAdLU=
+
+flush-write-stream@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
+ integrity sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.4"
+
+follow-redirects@^1.0.0:
+ version "1.5.10"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
+ integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
+ dependencies:
+ debug "=3.1.0"
+
+for-in@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+ integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+ integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
+ dependencies:
+ for-in "^1.0.1"
+
+for-own@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
+ integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
+ dependencies:
+ for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+ integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+
+fork-stream@^0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
+ integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
+
+form-data@~2.1.1:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
+ integrity sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.5"
+ mime-types "^2.1.12"
+
+form-data@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+ integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.6"
+ mime-types "^2.1.12"
+
+forwarded@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+ integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+from@^0.1.7, from@~0:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
+ integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=
+
+fs-exists-sync@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
+ integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
+
+fs-mkdirp-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb"
+ integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=
+ dependencies:
+ graceful-fs "^4.1.11"
+ through2 "^2.0.3"
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+function-bind@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+ integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+gaze@^0.5.1:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f"
+ integrity sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=
+ dependencies:
+ globule "~0.1.0"
+
+get-own-enumerable-property-symbols@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203"
+ integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==
+
+get-stdin@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+ integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+
+getpass@^0.1.1:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+ integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+ dependencies:
+ assert-plus "^1.0.0"
+
+gift@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/gift/-/gift-0.6.1.tgz#c1698e6b6887164ed978a01095423cff65b8e79f"
+ integrity sha1-wWmOa2iHFk7ZeKAQlUI8/2W4558=
+ dependencies:
+ underscore "1.x.x"
+
+glob-base@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+ integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
+ dependencies:
+ glob-parent "^2.0.0"
+ is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+ integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
+ dependencies:
+ is-glob "^2.0.0"
+
+glob-parent@^3.0.0, glob-parent@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+ integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+ dependencies:
+ is-glob "^3.1.0"
+ path-dirname "^1.0.0"
+
+glob-stream@^3.1.5:
+ version "3.1.18"
+ resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
+ integrity sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=
+ dependencies:
+ glob "^4.3.1"
+ glob2base "^0.0.12"
+ minimatch "^2.0.1"
+ ordered-read-streams "^0.1.0"
+ through2 "^0.6.1"
+ unique-stream "^1.0.0"
+
+glob-stream@^5.3.2:
+ version "5.3.5"
+ resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
+ integrity sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=
+ dependencies:
+ extend "^3.0.0"
+ glob "^5.0.3"
+ glob-parent "^3.0.0"
+ micromatch "^2.3.7"
+ ordered-read-streams "^0.3.0"
+ through2 "^0.6.0"
+ to-absolute-glob "^0.1.1"
+ unique-stream "^2.0.2"
+
+glob-stream@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4"
+ integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=
+ dependencies:
+ extend "^3.0.0"
+ glob "^7.1.1"
+ glob-parent "^3.1.0"
+ is-negated-glob "^1.0.0"
+ ordered-read-streams "^1.0.0"
+ pumpify "^1.3.5"
+ readable-stream "^2.1.5"
+ remove-trailing-separator "^1.0.1"
+ to-absolute-glob "^2.0.0"
+ unique-stream "^2.0.2"
+
+glob-watcher@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
+ integrity sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=
+ dependencies:
+ gaze "^0.5.1"
+
+glob2base@^0.0.12:
+ version "0.0.12"
+ resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
+ integrity sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=
+ dependencies:
+ find-index "^0.1.1"
+
+glob@^4.3.1:
+ version "4.5.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f"
+ integrity sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=
+ dependencies:
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^2.0.1"
+ once "^1.3.0"
+
+glob@^5.0.3:
+ version "5.0.15"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+ integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
+ dependencies:
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "2 || 3"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^7.0.5, glob@^7.1.1, glob@~7.1.1:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
+ integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.0.4"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@~3.1.21:
+ version "3.1.21"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd"
+ integrity sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=
+ dependencies:
+ graceful-fs "~1.2.0"
+ inherits "1"
+ minimatch "~0.2.11"
+
+global-modules@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
+ integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
+ dependencies:
+ global-prefix "^0.1.4"
+ is-windows "^0.2.0"
+
+global-prefix@^0.1.4:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
+ integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
+ dependencies:
+ homedir-polyfill "^1.0.0"
+ ini "^1.3.4"
+ is-windows "^0.2.0"
+ which "^1.2.12"
+
+globule@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5"
+ integrity sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=
+ dependencies:
+ glob "~3.1.21"
+ lodash "~1.0.1"
+ minimatch "~0.2.11"
+
+glogg@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810"
+ integrity sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==
+ dependencies:
+ sparkles "^1.0.0"
+
+graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+ version "4.1.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+ integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=
+
+graceful-fs@^3.0.0:
+ version "3.0.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818"
+ integrity sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=
+ dependencies:
+ natives "^1.1.0"
+
+graceful-fs@~1.2.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
+ integrity sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=
+
+gulp-angular-templatecache@^2.0.0:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/gulp-angular-templatecache/-/gulp-angular-templatecache-2.2.5.tgz#56393cf3f9982f2d931de3ff51d1170bfa40248f"
+ integrity sha512-BaNAVSt7lRQ7hRicUrVD7sBmXGUbkIE8iEjb0MUti7myg/4EfcadHIu9CMTbdjQc+UgyRAudCx6FHfR5QOZ0Ag==
+ dependencies:
+ event-stream "3.3.4"
+ gulp-concat "2.6.1"
+ gulp-footer "2.0.1"
+ gulp-header "2.0.5"
+ jsesc "2.5.1"
+ lodash.template "^4.4.0"
+ through2 "^2.0.3"
+
+gulp-chmod@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/gulp-chmod/-/gulp-chmod-2.0.0.tgz#00c390b928a0799b251accf631aa09e01cc6299c"
+ integrity sha1-AMOQuSigeZslGsz2MaoJ4BzGKZw=
+ dependencies:
+ deep-assign "^1.0.0"
+ stat-mode "^0.2.0"
+ through2 "^2.0.0"
+
+gulp-clean-css@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/gulp-clean-css/-/gulp-clean-css-4.0.0.tgz#1b67f1636e2b0da73499a7602396a0d570eb9626"
+ integrity sha512-/Hs+dmclQfFBSpwrAKd4wTVsahJvrVIg2ga0J7Eo7DKVTVfJrM7wXlfU1mK9iJ9Y7OmkO/YstZVtmhfAKzZ00g==
+ dependencies:
+ clean-css "4.2.1"
+ plugin-error "1.0.1"
+ through2 "3.0.0"
+ vinyl-sourcemaps-apply "0.2.1"
+
+gulp-clean@~0.3.0:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/gulp-clean/-/gulp-clean-0.3.2.tgz#a347d473acea40182f935587a451941671928102"
+ integrity sha1-o0fUc6zqQBgvk1WHpFGUFnGSgQI=
+ dependencies:
+ gulp-util "^2.2.14"
+ rimraf "^2.2.8"
+ through2 "^0.4.2"
+
+gulp-concat@2.6.1, gulp-concat@^2.0.0, gulp-concat@~2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353"
+ integrity sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=
+ dependencies:
+ concat-with-sourcemaps "^1.0.0"
+ through2 "^2.0.0"
+ vinyl "^2.0.0"
+
+gulp-debug@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/gulp-debug/-/gulp-debug-3.2.0.tgz#45aba4439fa79fe0788f6a411ee0778f4492dfa5"
+ integrity sha512-2LZzP+ydczqz1rhqq/NYxvVvYTmOa0IgBl2B1sQTdkQgku9ayOUM/KHuGPjF4QA5aO1VcG+Sskw7iCcRUqHKkA==
+ dependencies:
+ chalk "^2.3.0"
+ fancy-log "^1.3.2"
+ plur "^2.0.0"
+ stringify-object "^3.0.0"
+ through2 "^2.0.0"
+ tildify "^1.1.2"
+
+gulp-dedupe@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/gulp-dedupe/-/gulp-dedupe-0.0.2.tgz#36ef92adf7fcf53e2f096fbe9665d988f9e1ca7e"
+ integrity sha1-Nu+Srff89T4vCW++lmXZiPnhyn4=
+ dependencies:
+ colors "~1.0.2"
+ diff "~1.0.8"
+ gulp-util "~3.0.1"
+ lodash.defaults "~2.4.1"
+ through "~2.3.6"
+
+gulp-flatten@~0.3.0:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/gulp-flatten/-/gulp-flatten-0.3.1.tgz#51e7fec13a33c404578d18c1589d1b5bc45fe1d6"
+ integrity sha1-Uef+wTozxARXjRjBWJ0bW8Rf4dY=
+ dependencies:
+ gulp-util "^3.0.7"
+ through2 "^2.0.0"
+
+gulp-footer@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/gulp-footer/-/gulp-footer-2.0.1.tgz#76578359feb72aa280a97cb980bcfbe0e6216f3e"
+ integrity sha512-leXmoTEwXjklKuIE+8xGhuqlN/OdWubnkn3W/jNzmxxYbzQVjCtl2XI5iZztgPKLZ+Mh1t+7tTTGyVQqZva4+A==
+ dependencies:
+ event-stream "*"
+ lodash._reescape "^3.0.0"
+ lodash._reevaluate "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.template "^3.6.2"
+
+gulp-gh-pages@~0.5.0:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/gulp-gh-pages/-/gulp-gh-pages-0.5.4.tgz#a6732ca475ab9b5a53253c1c24734c40c21b6546"
+ integrity sha1-pnMspHWrm1pTJTwcJHNMQMIbZUY=
+ dependencies:
+ gift "^0.6.1"
+ gulp-util "^3.0.7"
+ readable-stream "^2.0.2"
+ rimraf "^2.4.3"
+ vinyl-fs "^2.2.1"
+ wrap-promise "^1.0.1"
+
+gulp-header@2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-2.0.5.tgz#16e229c73593ade301168024fea68dab75d9d38c"
+ integrity sha512-7bOIiHvM1GUHIG3LRH+UIanOxyjSys0FbzzgUBlV2cZIIZihEW+KKKKm0ejUBNGvRdhISEFFr6HlptXoa28gtQ==
+ dependencies:
+ concat-with-sourcemaps "*"
+ lodash.template "^4.4.0"
+ through2 "^2.0.0"
+
+gulp-header@^1.0.0:
+ version "1.8.12"
+ resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84"
+ integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==
+ dependencies:
+ concat-with-sourcemaps "*"
+ lodash.template "^4.4.0"
+ through2 "^2.0.0"
+
+gulp-if@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
+ integrity sha1-pJe351cwBQQcqivIt92jyARE1ik=
+ dependencies:
+ gulp-match "^1.0.3"
+ ternary-stream "^2.0.1"
+ through2 "^2.0.1"
+
+gulp-less@^3.0.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/gulp-less/-/gulp-less-3.5.0.tgz#8014f469ddfc6544d7dda50098def0371bbb4f78"
+ integrity sha512-FQLY7unaHdTOXG0jlwxeBQcWoPPrTMQZRA7HfYwSNi9IPVx5l7GJEN72mG4ri2yigp/f/VNGUAJnFMJHBmH3iw==
+ dependencies:
+ accord "^0.28.0"
+ less "2.6.x || ^2.7.1"
+ object-assign "^4.0.1"
+ plugin-error "^0.1.2"
+ replace-ext "^1.0.0"
+ through2 "^2.0.0"
+ vinyl-sourcemaps-apply "^0.2.0"
+
+gulp-load-plugins@^1.0.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/gulp-load-plugins/-/gulp-load-plugins-1.5.0.tgz#4c419f7e5764d9a0e33061bab9618f81b73d4171"
+ integrity sha1-TEGffldk2aDjMGG6uWGPgbc9QXE=
+ dependencies:
+ array-unique "^0.2.1"
+ fancy-log "^1.2.0"
+ findup-sync "^0.4.0"
+ gulplog "^1.0.0"
+ has-gulplog "^0.1.0"
+ micromatch "^2.3.8"
+ resolve "^1.1.7"
+
+gulp-match@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e"
+ integrity sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=
+ dependencies:
+ minimatch "^3.0.3"
+
+gulp-ng-annotate@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/gulp-ng-annotate/-/gulp-ng-annotate-2.0.0.tgz#84a83db1f016520bd70f9a5cfa9f3fe89e25a205"
+ integrity sha1-hKg9sfAWUgvXD5pc+p8/6J4logU=
+ dependencies:
+ bufferstreams "^1.1.0"
+ gulp-util "^3.0.7"
+ merge "^1.2.0"
+ ng-annotate "^1.2.1"
+ through2 "^2.0.1"
+ vinyl-sourcemaps-apply "^0.2.1"
+
+gulp-preprocess@~3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/gulp-preprocess/-/gulp-preprocess-3.0.1.tgz#ef16db8fe49c1da86e44d79c64c6ea7683fece16"
+ integrity sha512-YN0sU0IZD9fCiGcpTPPIkH3WaTqN+l6QDHkFy1Z2LT9db3w/raFarggDDIFMFEqiqM0pG2y7sQAdTMh6VDqjFg==
+ dependencies:
+ lodash "^4.17.10"
+ map-stream "^0.1.x"
+ preprocess "^3.0.0"
+
+gulp-rename@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.4.0.tgz#de1c718e7c4095ae861f7296ef4f3248648240bd"
+ integrity sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==
+
+gulp-replace@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/gulp-replace/-/gulp-replace-0.6.1.tgz#11bf8c8fce533e33e2f6a8f2f430b955ba0be066"
+ integrity sha1-Eb+Mj85TPjPi9qjy9DC5VboL4GY=
+ dependencies:
+ istextorbinary "1.0.2"
+ readable-stream "^2.0.1"
+ replacestream "^4.0.0"
+
+gulp-rev@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/gulp-rev/-/gulp-rev-9.0.0.tgz#fe51b181c5fbbebfe740b64748d6980827e82878"
+ integrity sha512-Ytx/uzDA2xNxHlPG8GReS1ut00msd0HlKDk9Ai/0xF2yvg+DAeGRAviCFlQzQmdZtqAoXznYspwWoGEoxDvhyA==
+ dependencies:
+ modify-filename "^1.1.0"
+ plugin-error "^1.0.1"
+ rev-hash "^2.0.0"
+ rev-path "^2.0.0"
+ sort-keys "^2.0.0"
+ through2 "^2.0.0"
+ vinyl "^2.1.0"
+ vinyl-file "^3.0.0"
+
+gulp-size@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/gulp-size/-/gulp-size-2.1.0.tgz#1c2b64f17f9071d5abd99d154b7b3481f8fba128"
+ integrity sha1-HCtk8X+QcdWr2Z0VS3s0gfj7oSg=
+ dependencies:
+ chalk "^1.0.0"
+ gulp-util "^3.0.0"
+ gzip-size "^3.0.0"
+ object-assign "^4.0.1"
+ pretty-bytes "^3.0.1"
+ stream-counter "^1.0.0"
+ through2 "^2.0.0"
+
+gulp-sourcemaps@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
+ integrity sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=
+ dependencies:
+ convert-source-map "^1.1.1"
+ graceful-fs "^4.1.2"
+ strip-bom "^2.0.0"
+ through2 "^2.0.0"
+ vinyl "^1.0.0"
+
+gulp-sourcemaps@^2.6.0:
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-2.6.4.tgz#cbb2008450b1bcce6cd23bf98337be751bf6e30a"
+ integrity sha1-y7IAhFCxvM5s0jv5gze+dRv24wo=
+ dependencies:
+ "@gulp-sourcemaps/identity-map" "1.X"
+ "@gulp-sourcemaps/map-sources" "1.X"
+ acorn "5.X"
+ convert-source-map "1.X"
+ css "2.X"
+ debug-fabulous "1.X"
+ detect-newline "2.X"
+ graceful-fs "4.X"
+ source-map "~0.6.0"
+ strip-bom-string "1.X"
+ through2 "2.X"
+
+gulp-tslint@^8.1.1:
+ version "8.1.3"
+ resolved "https://registry.yarnpkg.com/gulp-tslint/-/gulp-tslint-8.1.3.tgz#a89ed144038ae861ee7bfea9528272d126a93da1"
+ integrity sha512-KEP350N5B9Jg6o6jnyCyKVBPemJePYpMsGfIQq0G0ErvY7tw4Lrfb/y3L4WRf7ek0OsaE8nnj86w+lcLXW8ovw==
+ dependencies:
+ "@types/fancy-log" "1.3.0"
+ chalk "2.3.1"
+ fancy-log "1.3.2"
+ map-stream "~0.0.7"
+ plugin-error "1.0.1"
+ through "~2.3.8"
+
+gulp-typescript@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/gulp-typescript/-/gulp-typescript-4.0.2.tgz#80bb9e376e7aa87b763a6ad5fe054a5d078da1e6"
+ integrity sha512-Hhbn5Aa2l3T+tnn0KqsG6RRJmcYEsr3byTL2nBpNBeAK8pqug9Od4AwddU4JEI+hRw7mzZyjRbB8DDWR6paGVA==
+ dependencies:
+ ansi-colors "^1.0.1"
+ plugin-error "^0.1.2"
+ source-map "^0.6.1"
+ through2 "^2.0.3"
+ vinyl "^2.1.0"
+ vinyl-fs "^3.0.0"
+
+gulp-uglify@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-3.0.1.tgz#8d3eee466521bea6b10fd75dff72adf8b7ea2d97"
+ integrity sha512-KVffbGY9d4Wv90bW/B1KZJyunLMyfHTBbilpDvmcrj5Go0/a1G3uVpt+1gRBWSw/11dqR3coJ1oWNTt1AiXuWQ==
+ dependencies:
+ gulplog "^1.0.0"
+ has-gulplog "^0.1.0"
+ lodash "^4.13.1"
+ make-error-cause "^1.1.1"
+ safe-buffer "^5.1.2"
+ through2 "^2.0.0"
+ uglify-js "^3.0.5"
+ vinyl-sourcemaps-apply "^0.2.0"
+
+gulp-usemin@~0.3.0:
+ version "0.3.29"
+ resolved "https://registry.yarnpkg.com/gulp-usemin/-/gulp-usemin-0.3.29.tgz#f6846dc2903ff094b813c9edcc84c6c01761802e"
+ integrity sha512-khg8KQeMxJ/UTWt1N7YrHSnBpZAbfU89ij4wqHbUdmBPr/f0/fYhuQwhjydqCGvgfQwm1RuQaSsPfUmRMNr/7Q==
+ dependencies:
+ glob "~7.1.1"
+ gulp-concat "~2.6.1"
+ plugin-error "~1.0.1"
+ through2 "~2.0.3"
+ vinyl "~2.1.0"
+
+gulp-util@^2.2.14:
+ version "2.2.20"
+ resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-2.2.20.tgz#d7146e5728910bd8f047a6b0b1e549bc22dbd64c"
+ integrity sha1-1xRuVyiRC9jwR6awseVJvCLb1kw=
+ dependencies:
+ chalk "^0.5.0"
+ dateformat "^1.0.7-1.2.3"
+ lodash._reinterpolate "^2.4.1"
+ lodash.template "^2.4.1"
+ minimist "^0.2.0"
+ multipipe "^0.1.0"
+ through2 "^0.5.0"
+ vinyl "^0.2.1"
+
+gulp-util@^3.0.0, gulp-util@^3.0.7, gulp-util@~3.0.1:
+ version "3.0.8"
+ resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
+ integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08=
+ dependencies:
+ array-differ "^1.0.0"
+ array-uniq "^1.0.2"
+ beeper "^1.0.0"
+ chalk "^1.0.0"
+ dateformat "^2.0.0"
+ fancy-log "^1.1.0"
+ gulplog "^1.0.0"
+ has-gulplog "^0.1.0"
+ lodash._reescape "^3.0.0"
+ lodash._reevaluate "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.template "^3.0.0"
+ minimist "^1.1.0"
+ multipipe "^0.1.2"
+ object-assign "^3.0.0"
+ replace-ext "0.0.1"
+ through2 "^2.0.0"
+ vinyl "^0.5.0"
+
+gulp@^3.0.0:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4"
+ integrity sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=
+ dependencies:
+ archy "^1.0.0"
+ chalk "^1.0.0"
+ deprecated "^0.0.1"
+ gulp-util "^3.0.0"
+ interpret "^1.0.0"
+ liftoff "^2.1.0"
+ minimist "^1.1.0"
+ orchestrator "^0.3.0"
+ pretty-hrtime "^1.0.0"
+ semver "^4.1.0"
+ tildify "^1.0.0"
+ v8flags "^2.0.2"
+ vinyl-fs "^0.3.0"
+
+gulplog@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
+ integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U=
+ dependencies:
+ glogg "^1.0.0"
+
+gzip-size@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520"
+ integrity sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=
+ dependencies:
+ duplexer "^0.1.1"
+
+har-schema@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+ integrity sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=
+
+har-schema@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+ integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
+
+har-validator@~4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+ integrity sha1-M0gdDxu/9gDdID11gSpqX7oALio=
+ dependencies:
+ ajv "^4.9.1"
+ har-schema "^1.0.5"
+
+har-validator@~5.1.0:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
+ integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+ dependencies:
+ ajv "^6.5.5"
+ har-schema "^2.0.0"
+
+has-ansi@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e"
+ integrity sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=
+ dependencies:
+ ansi-regex "^0.2.0"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-gulplog@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
+ integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=
+ dependencies:
+ sparkles "^1.0.0"
+
+has-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+ integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
+
+hawk@~3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+ integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=
+ dependencies:
+ boom "2.x.x"
+ cryptiles "2.x.x"
+ hoek "2.x.x"
+ sntp "1.x.x"
+
+hoek@2.x.x:
+ version "2.16.3"
+ resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+ integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=
+
+homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
+ integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw=
+ dependencies:
+ parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
+ integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
+
+http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
+
+http-parser-js@>=0.4.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8"
+ integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w==
+
+http-proxy@^1.16.2:
+ version "1.17.0"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
+ integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==
+ dependencies:
+ eventemitter3 "^3.0.0"
+ follow-redirects "^1.0.0"
+ requires-port "^1.0.0"
+
+http-signature@~1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+ integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=
+ dependencies:
+ assert-plus "^0.2.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
+http-signature@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+ integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
+ dependencies:
+ assert-plus "^1.0.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
+iconv-lite@0.4.23:
+ version "0.4.23"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
+ integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+image-size@~0.5.0:
+ version "0.5.5"
+ resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
+ integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=
+
+indent-string@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+ integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+ dependencies:
+ repeating "^2.0.0"
+
+indx@^0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/indx/-/indx-0.2.3.tgz#15dcf56ee9cf65c0234c513c27fbd580e70fbc50"
+ integrity sha1-Fdz1bunPZcAjTFE8J/vVgOcPvFA=
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
+ integrity sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=
+
+inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@^1.3.4:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+ integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+interpret@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
+ integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=
+
+ipaddr.js@1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
+ integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4=
+
+irregular-plurals@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766"
+ integrity sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=
+
+is-absolute@^0.2.3:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb"
+ integrity sha1-IN5p89uULvLYe5wto28XIjWxtes=
+ dependencies:
+ is-relative "^0.2.1"
+ is-windows "^0.2.0"
+
+is-absolute@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
+ integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
+ dependencies:
+ is-relative "^1.0.0"
+ is-windows "^1.0.1"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-builtin-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+ integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74=
+ dependencies:
+ builtin-modules "^1.0.0"
+
+is-dotfile@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+ integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=
+
+is-equal-shallow@^0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+ integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
+ dependencies:
+ is-primitive "^2.0.0"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+ integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+ integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
+
+is-extglob@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-finite@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+ integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+ integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
+ dependencies:
+ is-extglob "^1.0.0"
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-negated-glob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2"
+ integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=
+
+is-number@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+ integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+ dependencies:
+ kind-of "^3.0.2"
+
+is-obj@^1.0.0, is-obj@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+ integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
+
+is-plain-obj@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
+ integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+ dependencies:
+ isobject "^3.0.1"
+
+is-posix-bracket@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+ integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
+
+is-primitive@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+ integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
+
+is-promise@^2.1:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+ integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
+
+is-regexp@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
+ integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
+
+is-relative@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5"
+ integrity sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=
+ dependencies:
+ is-unc-path "^0.1.1"
+
+is-relative@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
+ integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
+ dependencies:
+ is-unc-path "^1.0.0"
+
+is-stream@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+ integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-typedarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-unc-path@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9"
+ integrity sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=
+ dependencies:
+ unc-path-regex "^0.1.0"
+
+is-unc-path@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
+ integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
+ dependencies:
+ unc-path-regex "^0.1.2"
+
+is-utf8@^0.2.0, is-utf8@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+ integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+is-valid-glob@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
+ integrity sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=
+
+is-valid-glob@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa"
+ integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=
+
+is-windows@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
+ integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
+
+is-windows@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
+isarray@1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+ integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+
+istextorbinary@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-1.0.2.tgz#ace19354d1a9a0173efeb1084ce0f87b0ad7decf"
+ integrity sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=
+ dependencies:
+ binaryextensions "~1.0.0"
+ textextensions "~1.0.0"
+
+js-logger@^1.3.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/js-logger/-/js-logger-1.6.0.tgz#7abae5cfaf208c965f3ef20754533bb9e79c7aef"
+ integrity sha512-K4kt2AdD0jUYINbe00BPPpsL65u/rdYOgfaBBVWm/mid+ANk7qxDnoXgKI5ilm49Sjmach2Dzlc+5VxKdRA3tw==
+
+js-tokens@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+ integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
+
+js-yaml@^3.7.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
+ integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+jsbn@~0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+ integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
+
+jsesc@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe"
+ integrity sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema@0.2.3:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+ integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+
+json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+ integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=
+ dependencies:
+ jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+ integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
+
+jsonify@~0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+ integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
+
+jsprim@^1.2.2:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+ integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+ dependencies:
+ assert-plus "1.0.0"
+ extsprintf "1.3.0"
+ json-schema "0.2.3"
+ verror "1.10.0"
+
+kind-of@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44"
+ integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=
+
+kind-of@^3.0.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+ dependencies:
+ is-buffer "^1.1.5"
+
+lazy-cache@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+ integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
+
+lazystream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
+ integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
+ dependencies:
+ readable-stream "^2.0.5"
+
+lead@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42"
+ integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=
+ dependencies:
+ flush-write-stream "^1.0.2"
+
+"less@2.6.x || ^2.7.1":
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/less/-/less-2.7.3.tgz#cc1260f51c900a9ec0d91fb6998139e02507b63b"
+ integrity sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==
+ optionalDependencies:
+ errno "^0.1.1"
+ graceful-fs "^4.1.2"
+ image-size "~0.5.0"
+ mime "^1.2.11"
+ mkdirp "^0.5.0"
+ promise "^7.1.1"
+ request "2.81.0"
+ source-map "^0.5.3"
+
+liftoff@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385"
+ integrity sha1-qY8v9nGD2Lp8+soQVIvX/wVQs4U=
+ dependencies:
+ extend "^3.0.0"
+ findup-sync "^0.4.2"
+ fined "^1.0.1"
+ flagged-respawn "^0.3.2"
+ lodash.isplainobject "^4.0.4"
+ lodash.isstring "^4.0.1"
+ lodash.mapvalues "^4.4.0"
+ rechoir "^0.6.2"
+ resolve "^1.1.7"
+
+livereload-js@^2.3.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c"
+ integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==
+
+load-json-file@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+ integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+ strip-bom "^2.0.0"
+
+lodash._basecopy@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
+ integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=
+
+lodash._basetostring@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
+ integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=
+
+lodash._basevalues@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
+ integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=
+
+lodash._escapehtmlchar@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz#df67c3bb6b7e8e1e831ab48bfa0795b92afe899d"
+ integrity sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=
+ dependencies:
+ lodash._htmlescapes "~2.4.1"
+
+lodash._escapestringchar@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz#ecfe22618a2ade50bfeea43937e51df66f0edb72"
+ integrity sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=
+
+lodash._getnative@^3.0.0:
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+ integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
+
+lodash._htmlescapes@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz#32d14bf0844b6de6f8b62a051b4f67c228b624cb"
+ integrity sha1-MtFL8IRLbeb4tioFG09nwii2JMs=
+
+lodash._isiterateecall@^3.0.0:
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
+ integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=
+
+lodash._isnative@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._isnative/-/lodash._isnative-2.4.1.tgz#3ea6404b784a7be836c7b57580e1cdf79b14832c"
+ integrity sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=
+
+lodash._objecttypes@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz#7c0b7f69d98a1f76529f890b0cdb1b4dfec11c11"
+ integrity sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=
+
+lodash._reescape@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
+ integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=
+
+lodash._reevaluate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
+ integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=
+
+lodash._reinterpolate@^2.4.1, lodash._reinterpolate@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz#4f1227aa5a8711fc632f5b07a1f4607aab8b3222"
+ integrity sha1-TxInqlqHEfxjL1sHofRgequLMiI=
+
+lodash._reinterpolate@^3.0.0, lodash._reinterpolate@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+ integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
+
+lodash._reunescapedhtml@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz#747c4fc40103eb3bb8a0976e571f7a2659e93ba7"
+ integrity sha1-dHxPxAED6zu4oJduVx96JlnpO6c=
+ dependencies:
+ lodash._htmlescapes "~2.4.1"
+ lodash.keys "~2.4.1"
+
+lodash._root@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
+ integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
+
+lodash._shimkeys@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz#6e9cc9666ff081f0b5a6c978b83e242e6949d203"
+ integrity sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=
+ dependencies:
+ lodash._objecttypes "~2.4.1"
+
+lodash.clone@^4.3.2:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6"
+ integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=
+
+lodash.defaults@^4.0.1:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
+ integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
+
+lodash.defaults@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.4.1.tgz#a7e8885f05e68851144b6e12a8f3678026bc4c54"
+ integrity sha1-p+iIXwXmiFEUS24SqPNngCa8TFQ=
+ dependencies:
+ lodash._objecttypes "~2.4.1"
+ lodash.keys "~2.4.1"
+
+lodash.escape@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
+ integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=
+ dependencies:
+ lodash._root "^3.0.0"
+
+lodash.escape@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.4.1.tgz#2ce12c5e084db0a57dda5e5d1eeeb9f5d175a3b4"
+ integrity sha1-LOEsXghNsKV92l5dHu659dF1o7Q=
+ dependencies:
+ lodash._escapehtmlchar "~2.4.1"
+ lodash._reunescapedhtml "~2.4.1"
+ lodash.keys "~2.4.1"
+
+lodash.flatten@^4.2.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+ integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
+
+lodash.isarguments@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+ integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=
+
+lodash.isarray@^3.0.0:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+ integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
+
+lodash.isequal@^4.0.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+ integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
+
+lodash.isobject@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5"
+ integrity sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=
+ dependencies:
+ lodash._objecttypes "~2.4.1"
+
+lodash.isplainobject@^4.0.4:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+ integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
+
+lodash.isstring@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+ integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
+
+lodash.keys@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+ integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=
+ dependencies:
+ lodash._getnative "^3.0.0"
+ lodash.isarguments "^3.0.0"
+ lodash.isarray "^3.0.0"
+
+lodash.keys@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.4.1.tgz#48dea46df8ff7632b10d706b8acb26591e2b3727"
+ integrity sha1-SN6kbfj/djKxDXBrissmWR4rNyc=
+ dependencies:
+ lodash._isnative "~2.4.1"
+ lodash._shimkeys "~2.4.1"
+ lodash.isobject "~2.4.1"
+
+lodash.mapvalues@^4.4.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
+ integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
+
+lodash.merge@^4.4.0:
+ version "4.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
+ integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
+
+lodash.partialright@^4.1.4:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/lodash.partialright/-/lodash.partialright-4.2.1.tgz#0130d80e83363264d40074f329b8a3e7a8a1cc4b"
+ integrity sha1-ATDYDoM2MmTUAHTzKbij56ihzEs=
+
+lodash.pick@^4.2.1:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
+ integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
+
+lodash.restparam@^3.0.0:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
+ integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
+
+lodash.template@^2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.4.1.tgz#9e611007edf629129a974ab3c48b817b3e1cf20d"
+ integrity sha1-nmEQB+32KRKal0qzxIuBez4c8g0=
+ dependencies:
+ lodash._escapestringchar "~2.4.1"
+ lodash._reinterpolate "~2.4.1"
+ lodash.defaults "~2.4.1"
+ lodash.escape "~2.4.1"
+ lodash.keys "~2.4.1"
+ lodash.templatesettings "~2.4.1"
+ lodash.values "~2.4.1"
+
+lodash.template@^3.0.0, lodash.template@^3.6.2:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
+ integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=
+ dependencies:
+ lodash._basecopy "^3.0.0"
+ lodash._basetostring "^3.0.0"
+ lodash._basevalues "^3.0.0"
+ lodash._isiterateecall "^3.0.0"
+ lodash._reinterpolate "^3.0.0"
+ lodash.escape "^3.0.0"
+ lodash.keys "^3.0.0"
+ lodash.restparam "^3.0.0"
+ lodash.templatesettings "^3.0.0"
+
+lodash.template@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
+ integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=
+ dependencies:
+ lodash._reinterpolate "~3.0.0"
+ lodash.templatesettings "^4.0.0"
+
+lodash.templatesettings@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
+ integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=
+ dependencies:
+ lodash._reinterpolate "^3.0.0"
+ lodash.escape "^3.0.0"
+
+lodash.templatesettings@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316"
+ integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=
+ dependencies:
+ lodash._reinterpolate "~3.0.0"
+
+lodash.templatesettings@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz#ea76c75d11eb86d4dbe89a83893bb861929ac699"
+ integrity sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=
+ dependencies:
+ lodash._reinterpolate "~2.4.1"
+ lodash.escape "~2.4.1"
+
+lodash.uniq@^4.3.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+ integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
+
+lodash.values@~2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.4.1.tgz#abf514436b3cb705001627978cbcf30b1280eea4"
+ integrity sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=
+ dependencies:
+ lodash.keys "~2.4.1"
+
+lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4:
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
+ integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
+
+lodash@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
+ integrity sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=
+
+longest@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+ integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
+
+loud-rejection@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+ integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+ dependencies:
+ currently-unhandled "^0.4.1"
+ signal-exit "^3.0.0"
+
+lru-cache@2:
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
+ integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=
+
+lru-queue@0.1:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
+ integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=
+ dependencies:
+ es5-ext "~0.10.2"
+
+make-error-cause@^1.1.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d"
+ integrity sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=
+ dependencies:
+ make-error "^1.2.0"
+
+make-error@^1.2.0:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
+ integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
+
+map-cache@^0.2.0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+ integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-obj@^1.0.0, map-obj@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+ integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
+
+map-stream@0.0.7, map-stream@~0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8"
+ integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=
+
+map-stream@^0.1.x, map-stream@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
+ integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
+memoizee@0.4.X:
+ version "0.4.14"
+ resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57"
+ integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==
+ dependencies:
+ d "1"
+ es5-ext "^0.10.45"
+ es6-weak-map "^2.0.2"
+ event-emitter "^0.3.5"
+ is-promise "^2.1"
+ lru-queue "0.1"
+ next-tick "1"
+ timers-ext "^0.1.5"
+
+meow@^3.3.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+ integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
+ dependencies:
+ camelcase-keys "^2.0.0"
+ decamelize "^1.1.2"
+ loud-rejection "^1.0.0"
+ map-obj "^1.0.1"
+ minimist "^1.1.3"
+ normalize-package-data "^2.3.4"
+ object-assign "^4.0.1"
+ read-pkg-up "^1.0.1"
+ redent "^1.0.0"
+ trim-newlines "^1.0.0"
+
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
+merge-stream@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
+ integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=
+ dependencies:
+ readable-stream "^2.0.1"
+
+merge@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+ integrity sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+
+micromatch@^2.3.7, micromatch@^2.3.8:
+ version "2.3.11"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+ integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
+ dependencies:
+ arr-diff "^2.0.0"
+ array-unique "^0.2.1"
+ braces "^1.8.2"
+ expand-brackets "^0.1.4"
+ extglob "^0.3.1"
+ filename-regex "^2.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.1"
+ kind-of "^3.0.2"
+ normalize-path "^2.0.1"
+ object.omit "^2.0.0"
+ parse-glob "^3.0.4"
+ regex-cache "^0.4.2"
+
+mime-db@~1.36.0:
+ version "1.36.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397"
+ integrity sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==
+
+mime-db@~1.37.0:
+ version "1.37.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
+ integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==
+
+mime-types@^2.1.12, mime-types@~2.1.18, mime-types@~2.1.19:
+ version "2.1.21"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
+ integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==
+ dependencies:
+ mime-db "~1.37.0"
+
+mime-types@~2.1.7:
+ version "2.1.20"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19"
+ integrity sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==
+ dependencies:
+ mime-db "~1.36.0"
+
+mime@1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
+ integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
+
+mime@^1.2.11:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^2.0.1:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7"
+ integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=
+ dependencies:
+ brace-expansion "^1.0.0"
+
+minimatch@~0.2.11:
+ version "0.2.14"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a"
+ integrity sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=
+ dependencies:
+ lru-cache "2"
+ sigmund "~1.0.0"
+
+minimist@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+ integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.0.tgz#4dffe525dae2b864c66c2e23c6271d7afdecefce"
+ integrity sha1-Tf/lJdriuGTGbC4jxicdev3s784=
+
+minimist@^1.1.0, minimist@^1.1.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+ integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+minimist@~0.0.1:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+ integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+
+mkdirp@^0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+ dependencies:
+ minimist "0.0.8"
+
+modify-filename@^1.0.0, modify-filename@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/modify-filename/-/modify-filename-1.1.0.tgz#9a2dec83806fbb2d975f22beec859ca26b393aa1"
+ integrity sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+multipipe@^0.1.0, multipipe@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
+ integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=
+ dependencies:
+ duplexer2 "0.0.2"
+
+natives@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.1.tgz#011acce1f7cbd87f7ba6b3093d6cd9392be1c574"
+ integrity sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA==
+
+negotiator@0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
+ integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
+
+new-from@0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/new-from/-/new-from-0.0.3.tgz#1c4ad13613de3e15d6321b70ed5c23937ea25e67"
+ integrity sha1-HErRNhPePhXWMhtw7Vwjk36iXmc=
+ dependencies:
+ readable-stream "~1.1.8"
+
+next-tick@1:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
+ integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+
+ng-annotate@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/ng-annotate/-/ng-annotate-1.2.2.tgz#dc3fc51ba0b2f8b385dbe047f4da06f580a1fd61"
+ integrity sha1-3D/FG6Cy+LOF2+BH9NoG9YCh/WE=
+ dependencies:
+ acorn "~2.6.4"
+ alter "~0.2.0"
+ convert-source-map "~1.1.2"
+ optimist "~0.6.1"
+ ordered-ast-traverse "~1.1.1"
+ simple-fmt "~0.1.0"
+ simple-is "~0.2.0"
+ source-map "~0.5.3"
+ stable "~0.1.5"
+ stringmap "~0.2.2"
+ stringset "~0.2.1"
+ tryor "~0.1.2"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
+ integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==
+ dependencies:
+ hosted-git-info "^2.1.4"
+ is-builtin-module "^1.0.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1, normalize-path@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+ integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+ dependencies:
+ remove-trailing-separator "^1.0.1"
+
+now-and-later@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.0.tgz#bc61cbb456d79cb32207ce47ca05136ff2e7d6ee"
+ integrity sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=
+ dependencies:
+ once "^1.3.2"
+
+number-is-nan@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+ integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+oauth-sign@~0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+ integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=
+
+oauth-sign@~0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+ integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@4.X, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-assign@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
+ integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=
+
+object-keys@^1.0.11, object-keys@^1.0.12:
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
+ integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==
+
+object-keys@~0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336"
+ integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=
+
+object.assign@^4.0.4:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+ integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.1"
+ has-symbols "^1.0.0"
+ object-keys "^1.0.11"
+
+object.defaults@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
+ integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=
+ dependencies:
+ array-each "^1.0.1"
+ array-slice "^1.0.0"
+ for-own "^1.0.0"
+ isobject "^3.0.0"
+
+object.omit@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+ integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
+ dependencies:
+ for-own "^0.1.4"
+ is-extendable "^0.1.1"
+
+object.pick@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+ dependencies:
+ isobject "^3.0.1"
+
+on-finished@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+ integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+ dependencies:
+ ee-first "1.1.1"
+
+once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+ dependencies:
+ wrappy "1"
+
+once@~1.3.0:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
+ integrity sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=
+ dependencies:
+ wrappy "1"
+
+optimist@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+ integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+ dependencies:
+ minimist "~0.0.1"
+ wordwrap "~0.0.2"
+
+orchestrator@^0.3.0:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e"
+ integrity sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=
+ dependencies:
+ end-of-stream "~0.1.5"
+ sequencify "~0.0.7"
+ stream-consume "~0.1.0"
+
+ordered-ast-traverse@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ordered-ast-traverse/-/ordered-ast-traverse-1.1.1.tgz#6843a170bc0eee8b520cc8ddc1ddd3aa30fa057c"
+ integrity sha1-aEOhcLwO7otSDMjdwd3TqjD6BXw=
+ dependencies:
+ ordered-esprima-props "~1.1.0"
+
+ordered-esprima-props@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/ordered-esprima-props/-/ordered-esprima-props-1.1.0.tgz#a9827086df5f010aa60e9bd02b6e0335cea2ffcb"
+ integrity sha1-qYJwht9fAQqmDpvQK24DNc6i/8s=
+
+ordered-read-streams@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126"
+ integrity sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=
+
+ordered-read-streams@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
+ integrity sha1-cTfmmzKYuzQiR6G77jiByA4v14s=
+ dependencies:
+ is-stream "^1.0.1"
+ readable-stream "^2.0.1"
+
+ordered-read-streams@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e"
+ integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=
+ dependencies:
+ readable-stream "^2.0.1"
+
+os-homedir@^1.0.0, os-homedir@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+ integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+parse-filepath@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73"
+ integrity sha1-FZ1hVdQ5BNFsEO9piRHaHpGWm3M=
+ dependencies:
+ is-absolute "^0.2.3"
+ map-cache "^0.2.0"
+ path-root "^0.1.1"
+
+parse-glob@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+ integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
+ dependencies:
+ glob-base "^0.3.0"
+ is-dotfile "^1.0.0"
+ is-extglob "^1.0.0"
+ is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+ integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+ dependencies:
+ error-ex "^1.2.0"
+
+parse-passwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+ integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
+parseurl@~1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
+ integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=
+
+path-dirname@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+ integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-exists@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+ integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+ dependencies:
+ pinkie-promise "^2.0.0"
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-parse@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+ integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+
+path-root-regex@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+ integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=
+
+path-root@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+ integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=
+ dependencies:
+ path-root-regex "^0.1.0"
+
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
+path-type@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+ integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+ dependencies:
+ graceful-fs "^4.1.2"
+ pify "^2.0.0"
+ pinkie-promise "^2.0.0"
+
+pause-stream@0.0.11, pause-stream@^0.0.11:
+ version "0.0.11"
+ resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
+ integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=
+ dependencies:
+ through "~2.3"
+
+performance-now@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+ integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=
+
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+ integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+
+pify@^2.0.0, pify@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pinkie-promise@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+ integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+ dependencies:
+ pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+ integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+plugin-error@1.0.1, plugin-error@^1.0.1, plugin-error@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c"
+ integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==
+ dependencies:
+ ansi-colors "^1.0.1"
+ arr-diff "^4.0.0"
+ arr-union "^3.1.0"
+ extend-shallow "^3.0.2"
+
+plugin-error@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace"
+ integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=
+ dependencies:
+ ansi-cyan "^0.1.1"
+ ansi-red "^0.1.1"
+ arr-diff "^1.0.1"
+ arr-union "^2.0.1"
+ extend-shallow "^1.1.2"
+
+plur@^2.0.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a"
+ integrity sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=
+ dependencies:
+ irregular-plurals "^1.0.0"
+
+preprocess@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/preprocess/-/preprocess-3.1.0.tgz#a44e5cdd5bbb5a54f0ad289aaeed80995d7d938a"
+ integrity sha1-pE5c3Vu7WlTwrSiaru2AmV19k4o=
+ dependencies:
+ xregexp "3.1.0"
+
+preserve@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+ integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
+
+pretty-bytes@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-3.0.1.tgz#27d0008d778063a0b4811bb35c79f1bd5d5fbccf"
+ integrity sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=
+ dependencies:
+ number-is-nan "^1.0.0"
+
+pretty-hrtime@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
+ integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
+
+process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
+ integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
+
+process-nextick-args@~1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+ integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=
+
+promise@^7.1.1:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
+ integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
+ dependencies:
+ asap "~2.0.3"
+
+proxy-addr@~2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
+ integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==
+ dependencies:
+ forwarded "~0.1.2"
+ ipaddr.js "1.8.0"
+
+prr@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
+ integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
+
+psl@^1.1.24:
+ version "1.1.29"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
+ integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==
+
+pump@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+ integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+pumpify@^1.3.5:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+ integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
+ dependencies:
+ duplexify "^3.6.0"
+ inherits "^2.0.3"
+ pump "^2.0.0"
+
+punycode@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+ integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+qs@6.5.2, qs@~6.5.2:
+ version "6.5.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+ integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+
+qs@^6.4.0:
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.6.0.tgz#a99c0f69a8d26bf7ef012f871cdabb0aee4424c2"
+ integrity sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==
+
+qs@~6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+ integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=
+
+randomatic@^1.1.3:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
+ integrity sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+range-parser@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
+ integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
+
+raw-body@2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
+ integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==
+ dependencies:
+ bytes "3.0.0"
+ http-errors "1.6.3"
+ iconv-lite "0.4.23"
+ unpipe "1.0.0"
+
+raw-body@~1.1.0:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425"
+ integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=
+ dependencies:
+ bytes "1"
+ string_decoder "0.10"
+
+read-pkg-up@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+ integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+ dependencies:
+ find-up "^1.0.0"
+ read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+ integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+ dependencies:
+ load-json-file "^1.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^1.0.0"
+
+"readable-stream@2 || 3":
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.0.6.tgz#351302e4c68b5abd6a2ed55376a7f9a25be3057a"
+ integrity sha512-9E1oLoOWfhSXHGv6QlwXJim7uNzd9EVlWK+21tCU9Ju/kR0/p2AZYPz4qSchgO8PlLIH4FpZYfzwS+rEksZjIg==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17:
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+ integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c"
+ integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~1.0.6"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.0.3"
+ util-deprecate "~1.0.1"
+
+readable-stream@^2.1.5, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@~2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+ integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@~1.1.8, readable-stream@~1.1.9:
+ version "1.1.14"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+ integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
+ dependencies:
+ resolve "^1.1.6"
+
+redent@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+ integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+ dependencies:
+ indent-string "^2.1.0"
+ strip-indent "^1.0.1"
+
+regex-cache@^0.4.2:
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
+ integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
+ dependencies:
+ is-equal-shallow "^0.1.3"
+
+remove-bom-buffer@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
+ integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==
+ dependencies:
+ is-buffer "^1.1.5"
+ is-utf8 "^0.2.1"
+
+remove-bom-stream@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523"
+ integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=
+ dependencies:
+ remove-bom-buffer "^3.0.0"
+ safe-buffer "^5.1.0"
+ through2 "^2.0.3"
+
+remove-trailing-separator@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+ integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+repeat-element@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+ integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=
+
+repeat-string@^1.5.2:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+ integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+repeating@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+ integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
+ dependencies:
+ is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+ integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
+
+replace-ext@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
+ integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
+
+replacestream@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/replacestream/-/replacestream-4.0.3.tgz#3ee5798092be364b1cdb1484308492cb3dff2f36"
+ integrity sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==
+ dependencies:
+ escape-string-regexp "^1.0.3"
+ object-assign "^4.0.1"
+ readable-stream "^2.0.2"
+
+request@2.81.0:
+ version "2.81.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+ integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=
+ dependencies:
+ aws-sign2 "~0.6.0"
+ aws4 "^1.2.1"
+ caseless "~0.12.0"
+ combined-stream "~1.0.5"
+ extend "~3.0.0"
+ forever-agent "~0.6.1"
+ form-data "~2.1.1"
+ har-validator "~4.2.1"
+ hawk "~3.1.3"
+ http-signature "~1.1.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.7"
+ oauth-sign "~0.8.1"
+ performance-now "^0.2.0"
+ qs "~6.4.0"
+ safe-buffer "^5.0.1"
+ stringstream "~0.0.4"
+ tough-cookie "~2.3.0"
+ tunnel-agent "^0.6.0"
+ uuid "^3.0.0"
+
+request@^2.81.0:
+ version "2.88.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+ integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.0"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.4.3"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
+requires-port@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+ integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
+resolve-dir@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+ integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
+ dependencies:
+ expand-tilde "^1.2.2"
+ global-modules "^0.2.3"
+
+resolve-options@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131"
+ integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=
+ dependencies:
+ value-or-function "^3.0.0"
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+ integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+resolve@^1.1.6, resolve@^1.1.7:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
+ integrity sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==
+ dependencies:
+ path-parse "^1.0.5"
+
+resolve@^1.3.2, resolve@^1.5.0:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
+ integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==
+ dependencies:
+ path-parse "^1.0.5"
+
+rev-hash@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/rev-hash/-/rev-hash-2.0.0.tgz#7720a236ed0c258df3e64bec03ec048b05b924c4"
+ integrity sha1-dyCiNu0MJY3z5kvsA+wEiwW5JMQ=
+
+rev-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/rev-path/-/rev-path-2.0.0.tgz#10c978e824d76ce7dd1f7e66e88f50f5e71a0a6a"
+ integrity sha512-G5R2L9gYu9kEuqPfIFgO9gO+OhBWOAT83HyauOQmGHO6y9Fsa4acv+XsmNhNDrod0HDh1/VxJRmsffThzeHJlQ==
+ dependencies:
+ modify-filename "^1.0.0"
+
+right-align@^0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+ integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
+ dependencies:
+ align-text "^0.1.1"
+
+rimraf@^2.2.8, rimraf@^2.4.3:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
+ integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==
+ dependencies:
+ glob "^7.0.5"
+
+run-sequence@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/run-sequence/-/run-sequence-2.2.1.tgz#1ce643da36fd8c7ea7e1a9329da33fc2b8898495"
+ integrity sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==
+ dependencies:
+ chalk "^1.1.3"
+ fancy-log "^1.3.2"
+ plugin-error "^0.1.2"
+
+safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+ integrity sha1-0mPKVGls2KMGtcplUekt5XkY++c=
+
+safe-json-parse@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57"
+ integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+ integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+
+semver@^4.1.0:
+ version "4.3.6"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
+ integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=
+
+send@0.16.2:
+ version "0.16.2"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
+ integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
+ dependencies:
+ debug "2.6.9"
+ depd "~1.1.2"
+ destroy "~1.0.4"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "~1.6.2"
+ mime "1.4.1"
+ ms "2.0.0"
+ on-finished "~2.3.0"
+ range-parser "~1.2.0"
+ statuses "~1.4.0"
+
+sequencify@~0.0.7:
+ version "0.0.7"
+ resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c"
+ integrity sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=
+
+serve-static@1.13.2:
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
+ integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.2"
+ send "0.16.2"
+
+setprototypeof@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+ integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+sigmund@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
+ integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=
+
+signal-exit@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+ integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+simple-fmt@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b"
+ integrity sha1-GRv1ZqWeZTBILLJatTtKjchcOms=
+
+simple-is@~0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0"
+ integrity sha1-Krt1qt453rXMgVzhDmGRFkhQuvA=
+
+sntp@1.x.x:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+ integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=
+ dependencies:
+ hoek "2.x.x"
+
+sort-keys@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128"
+ integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=
+ dependencies:
+ is-plain-obj "^1.0.0"
+
+source-map-resolve@^0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
+ integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
+ dependencies:
+ atob "^2.1.1"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-url@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+ integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@^0.5.1, source-map@^0.5.3, source-map@~0.5.1, source-map@~0.5.3:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+sparkles@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c"
+ integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==
+
+spdx-correct@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.2.tgz#19bb409e91b47b1ad54159243f7312a858db3c2e"
+ integrity sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==
+ dependencies:
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+ integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+
+spdx-expression-parse@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+ integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz#e2a303236cac54b04031fa7a5a79c7e701df852f"
+ integrity sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==
+
+split@0.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
+ integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=
+ dependencies:
+ through "2"
+
+split@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
+ integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
+ dependencies:
+ through "2"
+
+sprintf-js@^1.0.3:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c"
+ integrity sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+sshpk@^1.7.0:
+ version "1.15.2"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.2.tgz#c946d6bd9b1a39d0e8635763f5242d6ed6dcb629"
+ integrity sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==
+ dependencies:
+ asn1 "~0.2.3"
+ assert-plus "^1.0.0"
+ bcrypt-pbkdf "^1.0.0"
+ dashdash "^1.12.0"
+ ecc-jsbn "~0.1.1"
+ getpass "^0.1.1"
+ jsbn "~0.1.0"
+ safer-buffer "^2.0.2"
+ tweetnacl "~0.14.0"
+
+stable@~0.1.3, stable@~0.1.5:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10"
+ integrity sha1-kQ9dKu17Ugxud3SZwfMuE5/eyxA=
+
+stat-mode@^0.2.0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502"
+ integrity sha1-5sgLYjEj19gM8TLOU480YokHJQI=
+
+"statuses@>= 1.4.0 < 2":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+statuses@~1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+ integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
+
+stream-combiner@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858"
+ integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=
+ dependencies:
+ duplexer "~0.1.1"
+ through "~2.3.4"
+
+stream-combiner@~0.0.4:
+ version "0.0.4"
+ resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14"
+ integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=
+ dependencies:
+ duplexer "~0.1.1"
+
+stream-consume@~0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
+ integrity sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=
+
+stream-counter@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/stream-counter/-/stream-counter-1.0.0.tgz#91cf2569ce4dc5061febcd7acb26394a5a114751"
+ integrity sha1-kc8lac5NxQYf6816yyY5SloRR1E=
+
+stream-shift@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
+ integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=
+
+string-template@~0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
+ integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
+
+string_decoder@0.10, string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+ integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
+
+string_decoder@^1.1.1, string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+string_decoder@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
+ integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+stringify-object@^3.0.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
+ integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
+ dependencies:
+ get-own-enumerable-property-symbols "^3.0.0"
+ is-obj "^1.0.1"
+ is-regexp "^1.0.0"
+
+stringmap@~0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1"
+ integrity sha1-VWwTeyWPlCuHdvWy71gqoGnX0bE=
+
+stringset@~0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5"
+ integrity sha1-7yWcTjSTRDd/zRyRPdLoSMnAQrU=
+
+stringstream@~0.0.4:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72"
+ integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==
+
+strip-ansi@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220"
+ integrity sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=
+ dependencies:
+ ansi-regex "^0.2.1"
+
+strip-ansi@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-bom-buf@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
+ integrity sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=
+ dependencies:
+ is-utf8 "^0.2.1"
+
+strip-bom-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
+ integrity sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=
+ dependencies:
+ first-chunk-stream "^1.0.0"
+ strip-bom "^2.0.0"
+
+strip-bom-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
+ integrity sha1-+H217yYT9paKpUWr/h7HKLaoKco=
+ dependencies:
+ first-chunk-stream "^2.0.0"
+ strip-bom "^2.0.0"
+
+strip-bom-string@1.X:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
+ integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=
+
+strip-bom@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794"
+ integrity sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=
+ dependencies:
+ first-chunk-stream "^1.0.0"
+ is-utf8 "^0.2.0"
+
+strip-bom@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+ integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+ dependencies:
+ is-utf8 "^0.2.0"
+
+strip-indent@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+ integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+ dependencies:
+ get-stdin "^4.0.1"
+
+supports-color@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a"
+ integrity sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+ integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+supports-color@^5.2.0, supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+ternary-stream@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269"
+ integrity sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=
+ dependencies:
+ duplexify "^3.5.0"
+ fork-stream "^0.0.4"
+ merge-stream "^1.0.0"
+ through2 "^2.0.1"
+
+textextensions@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-1.0.2.tgz#65486393ee1f2bb039a60cbba05b0b68bd9501d2"
+ integrity sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=
+
+through2-filter@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec"
+ integrity sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=
+ dependencies:
+ through2 "~2.0.0"
+ xtend "~4.0.0"
+
+through2@2.X, through2@^2.0.1, through2@~2.0.0, through2@~2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+ integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=
+ dependencies:
+ readable-stream "^2.1.5"
+ xtend "~4.0.1"
+
+through2@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.0.tgz#468b461df9cd9fcc170f22ebf6852e467e578ff2"
+ integrity sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ==
+ dependencies:
+ readable-stream "2 || 3"
+ xtend "~4.0.1"
+
+through2@^0.4.1, through2@^0.4.2:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b"
+ integrity sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=
+ dependencies:
+ readable-stream "~1.0.17"
+ xtend "~2.1.1"
+
+through2@^0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-0.5.1.tgz#dfdd012eb9c700e2323fd334f38ac622ab372da7"
+ integrity sha1-390BLrnHAOIyP9M084rGIqs3Lac=
+ dependencies:
+ readable-stream "~1.0.17"
+ xtend "~3.0.0"
+
+through2@^0.6.0, through2@^0.6.1:
+ version "0.6.5"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
+ integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=
+ dependencies:
+ readable-stream ">=1.0.33-1 <1.1.0-0"
+ xtend ">=4.0.0 <4.1.0-0"
+
+through2@^2.0.0, through2@^2.0.3:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+ integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+ dependencies:
+ readable-stream "~2.3.6"
+ xtend "~4.0.1"
+
+through@2, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.6, through@~2.3.8:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+tildify@^1.0.0, tildify@^1.1.2:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a"
+ integrity sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=
+ dependencies:
+ os-homedir "^1.0.0"
+
+time-stamp@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
+ integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=
+
+timers-ext@^0.1.5:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6"
+ integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==
+ dependencies:
+ es5-ext "~0.10.46"
+ next-tick "1"
+
+tiny-lr@^1.0.5:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab"
+ integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==
+ dependencies:
+ body "^5.1.0"
+ debug "^3.1.0"
+ faye-websocket "~0.10.0"
+ livereload-js "^2.3.0"
+ object-assign "^4.1.0"
+ qs "^6.4.0"
+
+to-absolute-glob@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
+ integrity sha1-HN+kcqnvUMI57maZm2YsoOs5k38=
+ dependencies:
+ extend-shallow "^2.0.1"
+
+to-absolute-glob@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b"
+ integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=
+ dependencies:
+ is-absolute "^1.0.0"
+ is-negated-glob "^1.0.0"
+
+to-through@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6"
+ integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=
+ dependencies:
+ through2 "^2.0.3"
+
+tough-cookie@~2.3.0:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
+ integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==
+ dependencies:
+ punycode "^1.4.1"
+
+tough-cookie@~2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+ integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
+ dependencies:
+ psl "^1.1.24"
+ punycode "^1.4.1"
+
+trim-newlines@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+ integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+
+tryor@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b"
+ integrity sha1-gUXkynyv9ArN48z5Rui4u3W0Fys=
+
+tslib@^1.8.0, tslib@^1.8.1:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
+ integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==
+
+tslint@^5.4.3:
+ version "5.11.0"
+ resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed"
+ integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0=
+ dependencies:
+ babel-code-frame "^6.22.0"
+ builtin-modules "^1.1.1"
+ chalk "^2.3.0"
+ commander "^2.12.1"
+ diff "^3.2.0"
+ glob "^7.1.1"
+ js-yaml "^3.7.0"
+ minimatch "^3.0.4"
+ resolve "^1.3.2"
+ semver "^5.3.0"
+ tslib "^1.8.0"
+ tsutils "^2.27.2"
+
+tsutils@^2.27.2:
+ version "2.29.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
+ integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
+ dependencies:
+ tslib "^1.8.1"
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
+ dependencies:
+ safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+ integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+
+type-is@~1.6.16:
+ version "1.6.16"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
+ integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.18"
+
+typescript@^3.0.0:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68"
+ integrity sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==
+
+uglify-js@^2.8.22:
+ version "2.8.29"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
+ integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
+ dependencies:
+ source-map "~0.5.1"
+ yargs "~3.10.0"
+ optionalDependencies:
+ uglify-to-browserify "~1.0.0"
+
+uglify-js@^3.0.5:
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
+ integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==
+ dependencies:
+ commander "~2.17.1"
+ source-map "~0.6.1"
+
+uglify-to-browserify@~1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+ integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
+
+ultron@~1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
+ integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==
+
+unc-path-regex@^0.1.0, unc-path-regex@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+ integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo=
+
+underscore.string@^3.0.0, underscore.string@^3.3.4:
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023"
+ integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==
+ dependencies:
+ sprintf-js "^1.0.3"
+ util-deprecate "^1.0.2"
+
+underscore@1.x.x:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
+ integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=
+
+unique-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
+ integrity sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=
+
+unique-stream@^2.0.2:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369"
+ integrity sha1-WqADz76Uxf+GbE59ZouxxNuts2k=
+ dependencies:
+ json-stable-stringify "^1.0.0"
+ through2-filter "^2.0.0"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ dependencies:
+ punycode "^2.1.0"
+
+urijs@^1.0.0, urijs@^1.18.10:
+ version "1.19.1"
+ resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.1.tgz#5b0ff530c0cbde8386f6342235ba5ca6e995d25a"
+ integrity sha512-xVrGVi94ueCJNrBSTjWqjvtgvl3cyOTThp2zaMaFNGp3F542TR6sM3f2o8RqZl+AwteClSVmoCyt0ka4RjQOQg==
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+ integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+url-join@^2.0.2:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
+ integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=
+
+user-home@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+ integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA=
+
+util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+uuid@^3.0.0, uuid@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
+ integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+
+v8flags@^2.0.2:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
+ integrity sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=
+ dependencies:
+ user-home "^1.1.1"
+
+vali-date@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
+ integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+ dependencies:
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
+
+value-or-function@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813"
+ integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+verror@1.10.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+ integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+ dependencies:
+ assert-plus "^1.0.0"
+ core-util-is "1.0.2"
+ extsprintf "^1.2.0"
+
+vinyl-file@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365"
+ integrity sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U=
+ dependencies:
+ graceful-fs "^4.1.2"
+ pify "^2.3.0"
+ strip-bom-buf "^1.0.0"
+ strip-bom-stream "^2.0.0"
+ vinyl "^2.0.1"
+
+vinyl-fs@^0.3.0:
+ version "0.3.14"
+ resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6"
+ integrity sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=
+ dependencies:
+ defaults "^1.0.0"
+ glob-stream "^3.1.5"
+ glob-watcher "^0.0.6"
+ graceful-fs "^3.0.0"
+ mkdirp "^0.5.0"
+ strip-bom "^1.0.0"
+ through2 "^0.6.1"
+ vinyl "^0.4.0"
+
+vinyl-fs@^2.2.1:
+ version "2.4.4"
+ resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
+ integrity sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=
+ dependencies:
+ duplexify "^3.2.0"
+ glob-stream "^5.3.2"
+ graceful-fs "^4.0.0"
+ gulp-sourcemaps "1.6.0"
+ is-valid-glob "^0.3.0"
+ lazystream "^1.0.0"
+ lodash.isequal "^4.0.0"
+ merge-stream "^1.0.0"
+ mkdirp "^0.5.0"
+ object-assign "^4.0.0"
+ readable-stream "^2.0.4"
+ strip-bom "^2.0.0"
+ strip-bom-stream "^1.0.0"
+ through2 "^2.0.0"
+ through2-filter "^2.0.0"
+ vali-date "^1.0.0"
+ vinyl "^1.0.0"
+
+vinyl-fs@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7"
+ integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==
+ dependencies:
+ fs-mkdirp-stream "^1.0.0"
+ glob-stream "^6.1.0"
+ graceful-fs "^4.0.0"
+ is-valid-glob "^1.0.0"
+ lazystream "^1.0.0"
+ lead "^1.0.0"
+ object.assign "^4.0.4"
+ pumpify "^1.3.5"
+ readable-stream "^2.3.3"
+ remove-bom-buffer "^3.0.0"
+ remove-bom-stream "^1.2.0"
+ resolve-options "^1.1.0"
+ through2 "^2.0.0"
+ to-through "^2.0.0"
+ value-or-function "^3.0.0"
+ vinyl "^2.0.0"
+ vinyl-sourcemap "^1.1.0"
+
+vinyl-map@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/vinyl-map/-/vinyl-map-1.0.2.tgz#a8b296025f973fa7cad62817967a48f1d176bf7c"
+ integrity sha1-qLKWAl+XP6fK1igXlnpI8dF2v3w=
+ dependencies:
+ bl "^1.1.2"
+ new-from "0.0.3"
+ through2 "^0.4.1"
+
+vinyl-sourcemap@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16"
+ integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=
+ dependencies:
+ append-buffer "^1.0.2"
+ convert-source-map "^1.5.0"
+ graceful-fs "^4.1.6"
+ normalize-path "^2.1.1"
+ now-and-later "^2.0.0"
+ remove-bom-buffer "^3.0.0"
+ vinyl "^2.0.0"
+
+vinyl-sourcemaps-apply@0.2.1, vinyl-sourcemaps-apply@^0.2.0, vinyl-sourcemaps-apply@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705"
+ integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=
+ dependencies:
+ source-map "^0.5.1"
+
+vinyl@^0.2.1:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.2.3.tgz#bca938209582ec5a49ad538a00fa1f125e513252"
+ integrity sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=
+ dependencies:
+ clone-stats "~0.0.1"
+
+vinyl@^0.4.0:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847"
+ integrity sha1-LzVsh6VQolVGHza76ypbqL94SEc=
+ dependencies:
+ clone "^0.2.0"
+ clone-stats "^0.0.1"
+
+vinyl@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
+ integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=
+ dependencies:
+ clone "^1.0.0"
+ clone-stats "^0.0.1"
+ replace-ext "0.0.1"
+
+vinyl@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
+ integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
+ dependencies:
+ clone "^1.0.0"
+ clone-stats "^0.0.1"
+ replace-ext "0.0.1"
+
+vinyl@^2.0.0, vinyl@^2.0.1, vinyl@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
+ integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==
+ dependencies:
+ clone "^2.1.1"
+ clone-buffer "^1.0.0"
+ clone-stats "^1.0.0"
+ cloneable-readable "^1.0.0"
+ remove-trailing-separator "^1.0.1"
+ replace-ext "^1.0.0"
+
+vinyl@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c"
+ integrity sha1-Ah+cLPlR1rk5lDyJ617lrdT9kkw=
+ dependencies:
+ clone "^2.1.1"
+ clone-buffer "^1.0.0"
+ clone-stats "^1.0.0"
+ cloneable-readable "^1.0.0"
+ remove-trailing-separator "^1.0.1"
+ replace-ext "^1.0.0"
+
+websocket-driver@>=0.5.1:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb"
+ integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=
+ dependencies:
+ http-parser-js ">=0.4.0"
+ websocket-extensions ">=0.1.1"
+
+websocket-extensions@>=0.1.1:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
+ integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
+
+when@^3.7.8:
+ version "3.7.8"
+ resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82"
+ integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=
+
+which@^1.2.12:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
+ integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==
+ dependencies:
+ isexe "^2.0.0"
+
+window-size@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+ integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
+
+wordwrap@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+ integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
+
+wordwrap@~0.0.2:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+ integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+
+wrap-promise@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/wrap-promise/-/wrap-promise-1.0.1.tgz#b019f4236ccbf1fb560921b4b4870b7bda2f5255"
+ integrity sha1-sBn0I2zL8ftWCSG0tIcLe9ovUlU=
+ dependencies:
+ es6-promise "^2.3.0"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+ws@^2.0.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80"
+ integrity sha1-a5Sz5EfLajY/eF6vlK9jWejoHIA=
+ dependencies:
+ safe-buffer "~5.0.1"
+ ultron "~1.1.0"
+
+xregexp@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-3.1.0.tgz#14d8461e0bdd38224bfee5039a0898fc42fcd336"
+ integrity sha1-FNhGHgvdOCJL/uUDmgiY/EL80zY=
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@~4.0.0, xtend@~4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+ integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
+
+xtend@~2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b"
+ integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os=
+ dependencies:
+ object-keys "~0.4.0"
+
+xtend@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a"
+ integrity sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=
+
+yargs@~3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+ integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
+ dependencies:
+ camelcase "^1.0.2"
+ cliui "^2.1.0"
+ decamelize "^1.0.0"
+ window-size "0.1.0"
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/pom.xml"
new file mode 100755
index 0000000..cfe8aa1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/pom.xml"
@@ -0,0 +1,45 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-core
+ ${project.artifactId}
+ hawtio :: hawtio-core
+
+
+
+
+
+
+ io.hawt
+ hawtio-util
+ ${project.version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ test
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/ConfigFacade.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/ConfigFacade.java"
new file mode 100755
index 0000000..b263640
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/ConfigFacade.java"
@@ -0,0 +1,108 @@
+package io.hawt.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import io.hawt.util.MBeanSupport;
+import io.hawt.util.Objects;
+import io.hawt.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A facade for the hawtio configuration features.
+ */
+public class ConfigFacade extends MBeanSupport implements ConfigFacadeMBean {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ConfigFacade.class);
+ private static ConfigFacade singleton;
+
+ private static Map urlStreamHandlerMap = new ConcurrentHashMap();
+ private String configDir;
+ private String version;
+
+ public static ConfigFacade getSingleton() {
+ if (singleton == null) {
+ LOG.debug("No ConfigFacade constructed yet so using default configuration for now");
+ singleton = new ConfigFacade();
+ }
+ return singleton;
+ }
+
+ @Override
+ public void init() throws Exception {
+ ConfigFacade.singleton = this;
+ super.init();
+ }
+
+ @Override
+ protected String getDefaultObjectName() {
+ return "hawtio:type=ConfigFacade";
+ }
+
+ @Override
+ public String getVersion() {
+ if (version == null) {
+ version = Objects.getVersion(getClass(), "io.hawt", "hawtio-core");
+ }
+ return version;
+ }
+
+ /**
+ * Returns the configuration directory; lazily attempting to create it if it does not yet exist
+ */
+ public File getConfigDirectory() {
+ String dirName = getConfigDir();
+ File answer = null;
+ if (Strings.isNotBlank(dirName)) {
+ answer = new File(dirName);
+ } else {
+ answer = new File(".hawtio");
+ }
+ answer.mkdirs();
+ return answer;
+ }
+
+ @Override
+ public String getConfigDir() {
+ if (Strings.isBlank(configDir)) {
+ // lets default to the users home directory
+ String home = System.getProperty("user.home", "~");
+ configDir = home + System.getProperty("hawtio.dirname", "/.hawtio");
+ }
+ return configDir;
+ }
+
+ public void setConfigDir(String configDir) {
+ this.configDir = configDir;
+ }
+
+ public InputStream openURL(String url) throws IOException {
+ int idx = url.indexOf(':');
+ if (idx > 1) {
+ String protocol = url.substring(0, idx);
+ String path = url.substring(idx + 1);
+ URLHandler urlHandler = getUrlHandler(protocol);
+ if (urlHandler != null) {
+ return urlHandler.openStream(path);
+ }
+ }
+ return new URL(url).openStream();
+ }
+
+ public URLHandler getUrlHandler(String protocol) {
+ return urlStreamHandlerMap.get(protocol);
+ }
+
+ public void addUrlHandler(String protocol, URLHandler handler) {
+ urlStreamHandlerMap.put(protocol, handler);
+ }
+
+ public void removeUrlHandler(String protocol) {
+ urlStreamHandlerMap.remove(protocol);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/ConfigFacadeMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/ConfigFacadeMBean.java"
new file mode 100755
index 0000000..4ae966f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/ConfigFacadeMBean.java"
@@ -0,0 +1,16 @@
+package io.hawt.config;
+
+/**
+ * The JMX MBean interface for working with hawtio configuration
+ */
+public interface ConfigFacadeMBean {
+ /**
+ * Returns the fully qualified path name where configuration is written.
+ */
+ String getConfigDir();
+
+ /**
+ * Returns the hawtio version
+ */
+ String getVersion();
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/URLHandler.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/URLHandler.java"
new file mode 100755
index 0000000..8f7530c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/java/io/hawt/config/URLHandler.java"
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.config;
+
+import java.io.InputStream;
+
+/**
+ * A facade above the URLStreamHandler interface so we can use URL handlers with different kinds of class loaders
+ * and registration rather than relying on the global classpath like the java.net.URL class
+ */
+public interface URLHandler {
+ /**
+ * Returns the stream to the given URL
+ */
+ InputStream openStream(String url);
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml"
new file mode 100755
index 0000000..073641d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/main/resources/OSGI-INF/blueprint/blueprint.xml"
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/test/java/io/hawt/config/ConfigFacadeTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/test/java/io/hawt/config/ConfigFacadeTest.java"
new file mode 100755
index 0000000..35f0e75
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/test/java/io/hawt/config/ConfigFacadeTest.java"
@@ -0,0 +1,47 @@
+package io.hawt.config;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+
+public class ConfigFacadeTest {
+ ConfigFacade facade = new ConfigFacade();
+
+ @Before
+ public void init() throws Exception {
+ facade.init();
+ }
+
+ @After
+ public void destroy() throws Exception {
+ facade.destroy();
+ }
+
+ @Test
+ public void testDefaultsToHomeDirectory() throws Exception {
+ File configDirectory = facade.getConfigDirectory();
+ assertTrue("the config directory should exist " + configDirectory, configDirectory.exists());
+ assertTrue("the config directory should be a directory " + configDirectory, configDirectory.isDirectory());
+ assertEquals("The config directory name", ".hawtio", configDirectory.getName());
+
+ File homeDir = new File(System.getProperty("user.home", "noHomeDir"));
+ File parentFile = configDirectory.getParentFile();
+ assertNotNull("Should have a parent directory", parentFile);
+
+ assertEquals("config dir should be in the home directory", homeDir.getCanonicalPath(), parentFile.getCanonicalPath());
+ }
+
+ @Test
+ public void testHasVersion() throws Exception {
+ String version = facade.getVersion();
+ System.out.println("Has version: " + version);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..70f6cb4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-core/src/test/resources/log4j.properties"
@@ -0,0 +1,18 @@
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, stdout, out
+
+#log4j.logger.io.hawt.introspect=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/test.log
+log4j.appender.out.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/.gitignore" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/.gitignore"
new file mode 100755
index 0000000..072a31e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/.gitignore"
@@ -0,0 +1,4 @@
+hawtio-config
+hawtio.log
+overlays
+mavenIndexer
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/pom.xml"
new file mode 100755
index 0000000..5655c7b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/pom.xml"
@@ -0,0 +1,173 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-default
+ war
+ ${project.artifactId}
+ hawtio :: Default Web Application
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${servlet-api-version}
+ provided
+
+
+
+ io.hawt
+ hawtio-base
+ ${project.version}
+
+ war
+
+
+
+
+ io.hawt
+ hawtio-core
+ ${project.version}
+ provided
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+ provided
+
+
+ org.apache.aries.blueprint
+ org.apache.aries.blueprint.web
+ ${blueprint-web-version}
+ provided
+
+
+ org.apache.geronimo.specs
+ geronimo-servlet_2.5_spec
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+
+
+ io.hawt
+ hawtio-log
+ ${project.version}
+
+
+ io.hawt
+ hawtio-ide
+ ${project.version}
+
+
+ io.hawt
+ hawtio-local-jvm-mbean
+ ${project.version}
+
+
+
+
+ commons-codec
+ commons-codec
+ ${commons-codec-version}
+
+
+ commons-logging
+ commons-logging
+ ${commons-logging-version}
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ **/lib/commons-logging-1.0.3.jar
+ false
+
+
+
+
+ ${jetty-plugin-groupId}
+ jetty-maven-plugin
+ ${jetty-version}
+
+ ${project.build.directory}/${project.name}
+ 1
+
+ ${context}
+
+
+
+ ${jettyPort}
+ 60000
+
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat7-maven-plugin
+ 2.0
+
+ 9090
+ ${context}
+
+
+ false
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat6-maven-plugin
+ 2.0
+
+ 9090
+ ${context}
+
+
+ false
+
+
+
+
+
+ maven-clean-plugin
+
+
+
+ ${basedir}/overlays
+
+ **/*.*
+
+ false
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/OSGI-INF/blueprint/blueprint.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/OSGI-INF/blueprint/blueprint.xml"
new file mode 100755
index 0000000..b2e8469
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/OSGI-INF/blueprint/blueprint.xml"
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/blueprint.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/blueprint.properties"
new file mode 100755
index 0000000..860fdbe
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/blueprint.properties"
@@ -0,0 +1,5 @@
+# the properties file used to override blueprint configuration properties:
+# http://aries.apache.org/modules/blueprintweb.html
+#
+# for hawtio configuration options see:
+# https://github.com/hawtio/hawtio/blob/master/docs/Configuration.md
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/log4j.properties"
new file mode 100755
index 0000000..e0d1274
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/resources/log4j.properties"
@@ -0,0 +1,14 @@
+log4j.rootLogger=INFO, console
+
+# Console will only display warnnings
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n
+log4j.appender.console.threshold=INFO
+
+# File appender will contain all info messages
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n
+log4j.appender.file.file=${user.home}/.hawtio/logs/hawtio.log
+log4j.appender.file.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/webapp/.gitignore" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-default/src/main/webapp/.gitignore"
new file mode 100755
index 0000000..e69de29
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/.gitignore" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/.gitignore"
new file mode 100755
index 0000000..9698a7c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/.gitignore"
@@ -0,0 +1 @@
+hawtio-config
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/pom.xml"
new file mode 100755
index 0000000..ca7c157
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/pom.xml"
@@ -0,0 +1,98 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-embedded
+ ${project.artifactId}
+ hawtio :: hawtio-embedded
+
+
+
+ org.eclipse.jetty
+ jetty-webapp
+ ${jetty-version}
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${jetty-version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+ org.apache.httpcomponents
+ fluent-hc
+ ${httpclient-version}
+ test
+
+
+ io.hawt
+ hawtio-default
+ ${project.version}
+ war
+ test
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ ${exec-maven-plugin-version}
+
+
+
+ java
+
+
+
+
+ io.hawt.embedded.Main
+ test
+
+ --warLocation
+ ${basedir}/../hawtio-default/target
+ --port
+ ${jettyPort}
+ --contextPath
+ ${context}
+
+
+
+ basedir
+ ${basedir}
+
+
+ hawtio.authenticationEnabled
+ false
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/main/java/io/hawt/embedded/Main.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/main/java/io/hawt/embedded/Main.java"
new file mode 100755
index 0000000..b90759b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/main/java/io/hawt/embedded/Main.java"
@@ -0,0 +1,324 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.embedded;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Slf4jLog;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+/**
+ * A simple way to run hawtio embedded inside a JVM by booting up a Jetty server
+ */
+public class Main {
+ private Options options;
+ private boolean welcome = true;
+
+ public Main() {
+ options = new Options();
+ options.init();
+ }
+
+ public static void main(String[] args) {
+ Main main = new Main();
+
+ if (!main.parseArguments(args) || main.isHelp()) {
+ main.showOptions();
+ return;
+ }
+
+ doRun(main);
+ }
+
+ public boolean parseArguments(String[] args) {
+ return options.parseArguments(args);
+ }
+
+ public void showOptions() {
+ options.showOptions();
+ }
+
+ public static void doRun(Main main) {
+ try {
+ main.run();
+ } catch (Exception e) {
+ System.out.println("Error: " + e);
+ e.printStackTrace();
+ }
+ }
+
+ public void run() throws Exception {
+ run(options.isJointServerThread());
+ }
+
+ public void run(boolean join) throws Exception {
+ System.setProperty("org.eclipse.jetty.util.log.class", Slf4jLog.class.getName());
+ Slf4jLog log = new Slf4jLog("jetty");
+ Log.setLog(log);
+
+ Server server = new Server(new InetSocketAddress(InetAddress.getByName(options.getHost()), options.getPort()));
+
+ HandlerCollection handlers = new HandlerCollection();
+ handlers.setServer(server);
+ server.setHandler(handlers);
+ String scheme = "http";
+ if (null != options.getKeyStore()) {
+ System.out.println("Configuring SSL");
+ SslContextFactory sslcontf = new SslContextFactory();
+ HttpConfiguration httpconf = new HttpConfiguration();
+ sslcontf.setKeyStorePath(options.getKeyStore());
+ if (null != options.getKeyStorePass()) {
+ sslcontf.setKeyStorePassword(options.getKeyStorePass());
+ } else {
+ System.out.println("Attempting to open keystore with no password...");
+ }
+ try (ServerConnector sslconn = new ServerConnector(server, new SslConnectionFactory(sslcontf, "http/1.1"), new HttpConnectionFactory(httpconf));) {
+ sslconn.setPort(options.getPort());
+ server.setConnectors(new Connector[] { sslconn });
+
+ }
+ scheme = "https";
+ }
+ String sysScheme = System.getProperty("hawtio.redirect.scheme");
+ if (null == sysScheme) {
+ System.out.println("Implicitly setting Scheme = " + scheme);
+ System.setProperty("hawtio.redirect.scheme", scheme);
+ } else {
+ System.out.println("Scheme Was Set Explicitly To = " + scheme);
+ scheme = sysScheme;
+ }
+ WebAppContext webapp = new WebAppContext();
+ webapp.setServer(server);
+ webapp.setContextPath(options.getContextPath());
+ String war = findWar(options.getWarLocation());
+ if (war == null) {
+ war = options.getWar();
+ }
+ if (war == null) {
+ throw new IllegalArgumentException("No war or warLocation options set!");
+ }
+ webapp.setWar(war);
+ webapp.setParentLoaderPriority(true);
+ webapp.setLogUrlOnStart(true);
+ webapp.setInitParameter("scheme", scheme);
+ webapp.setExtraClasspath(options.getExtraClassPath());
+
+ // lets set a temporary directory so jetty doesn't bork if some process zaps /tmp/*
+ String homeDir = System.getProperty("user.home", ".") + "/.hawtio";
+ String tempDirPath = homeDir + "/tmp";
+ File tempDir = new File(tempDirPath);
+ tempDir.mkdirs();
+ log.info("using temp directory for jetty: " + tempDir.getPath());
+ webapp.setTempDirectory(tempDir);
+
+ // check for 3rd party plugins before we add hawtio, so they are initialized before hawtio
+ findThirdPartyPlugins(log, handlers, tempDir);
+
+ // add hawtio
+ handlers.addHandler(webapp);
+
+ // create server and add the handlers
+ if (welcome) {
+ System.out.println("Embedded Hawtio: You can use --help to show usage");
+ System.out.println(options.usedOptionsSummary());
+ }
+
+ System.out.println("About to start Hawtio " + war);
+ server.start();
+
+ if (welcome) {
+ System.out.println();
+ System.out.println("Welcome to Hawtio");
+ System.out.println("=====================================================");
+ System.out.println();
+ System.out.println(scheme + "://localhost:" + options.getPort() + options.getContextPath());
+ System.out.println();
+ }
+
+ if (join) {
+ if (welcome) {
+ System.out.println("Joining the Jetty server thread");
+ }
+ server.join();
+ }
+ }
+
+ protected void findThirdPartyPlugins(Slf4jLog log, HandlerCollection handlers, File tempDir) {
+ File dir = new File(options.getPlugins());
+ if (dir.exists() && dir.isDirectory()) {
+
+ log.info("Scanning for 3rd party plugins in directory: " + dir.getName());
+
+ // find any .war files
+ File[] wars = dir.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return isWarFileName(name);
+ }
+ });
+ if (wars != null) {
+ for (File war : wars) {
+
+ // custom plugins must not use same context-path as hawtio
+ String contextPath = "/" + war.getName();
+ if (contextPath.endsWith(".war")) {
+ contextPath = contextPath.substring(0, contextPath.length() - 4);
+ }
+ if (contextPath.equals(options.getContextPath())) {
+ throw new IllegalArgumentException("3rd party plugin " + war.getName() + " cannot have same name as Hawtio context path. Rename the plugin file to avoid the clash.");
+ }
+
+ WebAppContext plugin = new WebAppContext();
+ plugin.setServer(handlers.getServer());
+ plugin.setContextPath(contextPath);
+ plugin.setWar(war.getAbsolutePath());
+ // plugin.setParentLoaderPriority(true);
+ plugin.setLogUrlOnStart(true);
+
+ // need to have private sub directory for each plugin
+ File pluginTempDir = new File(tempDir, war.getName());
+ pluginTempDir.mkdirs();
+
+ plugin.setTempDirectory(pluginTempDir);
+ plugin.setThrowUnavailableOnStartupException(true);
+
+ try {
+ plugin.start();
+ handlers.addHandler(plugin);
+
+ log.info("Added 3rd party plugin with context-path: " + contextPath);
+ System.out.println("Added 3rd party plugin with context-path: " + contextPath);
+ } catch (Exception e) {
+ log.warn("Failed to add and start 3rd party plugin with context-path: " + contextPath + " due " + e.getMessage(), e);
+ }
+ }
+ }
+
+ }
+ }
+
+ /**
+ * Strategy method where we could use some smarts to find the war
+ * using known paths or maybe the local maven repository?
+ */
+ protected String findWar(String... paths) {
+ if (paths != null) {
+ for (String path : paths) {
+ if (path != null) {
+ File file = new File(path);
+ if (file.exists()) {
+ if (file.isFile()) {
+ String name = file.getName();
+ if (isWarFileName(name)) {
+ return file.getPath();
+ }
+ }
+ if (file.isDirectory()) {
+ // lets look for a war in this directory
+ File[] wars = file.listFiles((dir, name) -> isWarFileName(name));
+ if (wars != null && wars.length > 0) {
+ return wars[0].getPath();
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ protected boolean isWarFileName(String name) {
+ return name.toLowerCase().endsWith(".war");
+ }
+
+ public String getWarLocation() {
+ return options.getWarLocation();
+ }
+
+ public void setWarLocation(String warLocation) {
+ options.setWarLocation(warLocation);
+ }
+
+ public String getWar() {
+ return options.getWar();
+ }
+
+ public void setWar(String war) {
+ options.setWar(war);
+ }
+
+ public String getContextPath() {
+ return options.getContextPath();
+ }
+
+ public void setContextPath(String contextPath) {
+ options.setContextPath(contextPath);
+ }
+
+ public Integer getPort() {
+ return options.getPort();
+ }
+
+ public void setPort(Integer port) {
+ options.setPort(port);
+ }
+
+ public String getExtraClassPath() {
+ return options.getExtraClassPath();
+ }
+
+ public void setExtraClassPath(String extraClassPath) {
+ options.setExtraClassPath(extraClassPath);
+ }
+
+ public boolean isJoinServerThread() {
+ return options.isJointServerThread();
+ }
+
+ public void setJoinServerThread(boolean joinServerThread) {
+ options.setJointServerThread(joinServerThread);
+ }
+
+ public boolean isOpenUrl() {
+ return options.isOpenUrl();
+ }
+
+ public void setOpenUrl(boolean openUrl) {
+ options.setOpenUrl(openUrl);
+ }
+
+ public boolean isHelp() {
+ return options.isHelp();
+ }
+
+ public void showWelcome(boolean welcome) {
+ this.welcome = welcome;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/main/java/io/hawt/embedded/Options.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/main/java/io/hawt/embedded/Options.java"
new file mode 100755
index 0000000..c0a0668
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/main/java/io/hawt/embedded/Options.java"
@@ -0,0 +1,351 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.embedded;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Options {
+
+ private final List options = new ArrayList<>();
+ private String warLocation;
+ private String war;
+ private String contextPath = "/hawtio";
+ private String plugins = "plugins";
+ private String host = "0.0.0.0";
+ private Integer port = 8080;
+ private String extraClassPath;
+ private boolean help;
+ private boolean jointServerThread;
+ private boolean openUrl = true;
+ private String keyStore = null;
+ private String keyStorePass = null;
+
+ private abstract class Option {
+ private String abbreviation;
+ private String fullName;
+ private String description;
+
+ protected Option(String abbreviation, String fullName, String description) {
+ this.abbreviation = "-" + abbreviation;
+ this.fullName = "--" + fullName;
+ this.description = description;
+ }
+
+ public boolean processOption(String arg, LinkedList remainingArgs) {
+ if (arg.equalsIgnoreCase(abbreviation) || fullName.startsWith(arg)) {
+ doProcess(arg, remainingArgs);
+ return true;
+ }
+ return false;
+ }
+
+ public String getAbbreviation() {
+ return abbreviation;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getFullName() {
+ return fullName;
+ }
+
+ public String getInformation() {
+ return " " + getAbbreviation() + " or " + getFullName() + " = " + getDescription();
+ }
+
+ protected abstract void doProcess(String arg, LinkedList remainingArgs);
+ }
+
+ private abstract class ParameterOption extends Option {
+
+ protected ParameterOption(String abbreviation, String fullName, String description) {
+ super(abbreviation, fullName, description);
+ }
+
+ protected void doProcess(String arg, LinkedList remainingArgs) {
+ if (remainingArgs.isEmpty()) {
+ System.err.println("Expected fileName for ");
+ showOptions();
+ } else {
+ String parameter = remainingArgs.removeFirst();
+ doProcess(arg, parameter, remainingArgs);
+ }
+ }
+
+ public String getInformation() {
+ return " " + getAbbreviation() + " or " + getFullName() + " = " + getDescription();
+ }
+
+ protected abstract void doProcess(String arg, String parameter, LinkedList remainingArgs);
+ }
+
+ public void init() {
+ addOption(new Option("h", "help", "Displays the help screen") {
+ protected void doProcess(String arg, LinkedList remainingArgs) {
+ help = true;
+ }
+ });
+
+ addOption(new ParameterOption("j", "join", "Join server thread") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ jointServerThread = Boolean.valueOf(parameter);
+ }
+ });
+
+ addOption(new ParameterOption("w", "war", "War file or directory of the hawtio web application") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ war = parameter;
+ }
+ });
+
+ addOption(new ParameterOption("l", "warLocation", "Directory to search for .war files") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ warLocation = parameter;
+ }
+ });
+
+ addOption(new ParameterOption("pd", "pluginsDir", "Directory to search for .war files to install as 3rd party plugins") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ plugins = parameter;
+ }
+ });
+
+ addOption(new ParameterOption("c", "contextPath", "Context path") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ // must have leading slash
+ if (!parameter.startsWith("/")) {
+ contextPath = "/" + parameter;
+ } else {
+ contextPath = parameter;
+ }
+ }
+ });
+
+ addOption(new ParameterOption("hst", "host", "Hostname to listen to") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ host = parameter;
+ }
+ });
+
+ addOption(new ParameterOption("p", "port", "Port number") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ try {
+ port = Integer.parseInt(parameter);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid port number " + parameter + " due " + e.getMessage());
+ }
+ }
+ });
+
+ addOption(new ParameterOption("ecp", "extraClassPath", "Extra classpath") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ extraClassPath = parameter;
+ }
+ });
+
+ addOption(new ParameterOption("ou", "openUrl", "Open the web console automatic in the web browser") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ openUrl = Boolean.valueOf(parameter);
+ }
+ });
+ addOption(new ParameterOption("ks", "keyStore", "JKS keyStore with the keys for https") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ keyStore = parameter;
+ }
+ });
+ addOption(new ParameterOption("kp", "keyStorePass", "password for the JKS keyStore with the keys for https") {
+ protected void doProcess(String arg, String parameter, LinkedList remainingArgs) {
+ keyStorePass = parameter;
+ }
+ });
+
+ }
+
+ private void addOption(Option option) {
+ options.add(option);
+ }
+
+ public void showOptions() {
+ System.out.println("hawtio takes the following options");
+ System.out.println();
+ for (Option option : options) {
+ System.out.println(option.getInformation());
+ }
+ System.out.println();
+ System.out.println();
+ }
+
+ public String usedOptionsSummary() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Using options [");
+ if (war != null) {
+ sb.append("\n\twar=").append(war);
+ }
+ if (warLocation != null) {
+ sb.append("\n\twarLocation=").append(warLocation);
+ }
+ if (contextPath != null) {
+ sb.append("\n\tcontextPath=").append(contextPath);
+ }
+ if (host != null) {
+ sb.append("\n\thost=").append(host);
+ }
+ if (port != null) {
+ sb.append("\n\tport=").append(port);
+ }
+ if (extraClassPath != null) {
+ sb.append("\n\textraClassPath=").append(extraClassPath);
+ }
+ if (plugins != null) {
+ sb.append("\n\tplugins=").append(plugins);
+ }
+ if (keyStore != null) {
+ sb.append("\n\tkeyStore=").append(keyStore);
+ }
+ if (keyStorePass != null) {
+ sb.append("\n\tkeyStore=").append(keyStorePass);
+ }
+ sb.append("\n\topenUrl=").append(openUrl);
+ sb.append("\n\tjointServerThread=").append(jointServerThread);
+ sb.append("\n\thelp=").append(help);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public boolean parseArguments(String[] arguments) {
+ LinkedList args = new LinkedList<>(Arrays.asList(arguments));
+
+ boolean valid = true;
+ while (!args.isEmpty()) {
+ String arg = args.removeFirst();
+
+ boolean handled = false;
+ for (Option option : options) {
+ if (option.processOption(arg, args)) {
+ handled = true;
+ break;
+ }
+ }
+ if (!handled) {
+ System.out.println("Error: Unknown option: " + arg);
+ System.out.println();
+ valid = false;
+ break;
+ }
+ }
+
+ return valid;
+ }
+
+ public String getWar() {
+ return war;
+ }
+
+ public void setWar(String war) {
+ this.war = war;
+ }
+
+ public String getWarLocation() {
+ return warLocation;
+ }
+
+ public void setWarLocation(String warLocation) {
+ this.warLocation = warLocation;
+ }
+
+ public String getContextPath() {
+ return contextPath;
+ }
+
+ public void setContextPath(String contextPath) {
+ this.contextPath = contextPath;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+
+ public void setPort(Integer port) {
+ this.port = port;
+ }
+
+ public String getPlugins() {
+ return plugins;
+ }
+
+ public void setPlugins(String plugins) {
+ this.plugins = plugins;
+ }
+
+ public String getExtraClassPath() {
+ return extraClassPath;
+ }
+
+ public void setExtraClassPath(String extraClassPath) {
+ this.extraClassPath = extraClassPath;
+ }
+
+ public boolean isJointServerThread() {
+ return jointServerThread;
+ }
+
+ public void setJointServerThread(boolean jointServerThread) {
+ this.jointServerThread = jointServerThread;
+ }
+
+ public boolean isOpenUrl() {
+ return openUrl;
+ }
+
+ public void setOpenUrl(boolean openUrl) {
+ this.openUrl = openUrl;
+ }
+
+ public boolean isHelp() {
+ return help;
+ }
+
+ public String getKeyStore() {
+ return keyStore;
+ }
+
+ public void setKeyStore(String keyStore) {
+ this.keyStore = keyStore;
+ }
+
+ public String getKeyStorePass() {
+ return keyStorePass;
+ }
+
+ public void setKeyStorePass(String keyStorePass) {
+ this.keyStorePass = keyStorePass;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/test/java/io/hawt/embedded/MainTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/test/java/io/hawt/embedded/MainTest.java"
new file mode 100755
index 0000000..4344a74
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/test/java/io/hawt/embedded/MainTest.java"
@@ -0,0 +1,27 @@
+package io.hawt.embedded;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.fluent.Request;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class MainTest {
+
+ @Test
+ public void run() throws Exception {
+ System.setProperty("hawtio.authenticationEnabled", "false");
+ int port = 12345;
+
+ Main main = new Main();
+ main.setWarLocation("../hawtio-default/target/");
+ main.setPort(port);
+ main.run();
+
+ HttpResponse response = Request.Get(String.format("http://localhost:%s/hawtio/jolokia/version", port))
+ .execute().returnResponse();
+ assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..b47e212
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-embedded/src/test/resources/log4j.properties"
@@ -0,0 +1,16 @@
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, stdout, out
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/hawtio-embedded-test.log
+log4j.appender.out.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/pom.xml"
new file mode 100755
index 0000000..cbc55b8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/pom.xml"
@@ -0,0 +1,45 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-ide
+ ${project.artifactId}
+ hawtio :: hawtio-ide
+
+
+
+
+
+
+ io.hawt
+ hawtio-util
+ ${project.version}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ test
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/java/io/hawt/ide/IdeFacade.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/java/io/hawt/ide/IdeFacade.java"
new file mode 100755
index 0000000..d78326f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/java/io/hawt/ide/IdeFacade.java"
@@ -0,0 +1,187 @@
+package io.hawt.ide;
+
+import io.hawt.util.IOHelper;
+import io.hawt.util.MBeanSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+
+/**
+ * A facade for working with IDEs
+ */
+public class IdeFacade extends MBeanSupport implements IdeFacadeMBean {
+ private static final transient Logger LOG = LoggerFactory.getLogger(IdeFacade.class);
+ private static IdeFacade singleton;
+ private File baseDir;
+
+ public static IdeFacade getSingleton() {
+ if (singleton == null) {
+ LOG.warn("No IdeFacade constructed yet so using default configuration for now");
+ singleton = new IdeFacade();
+ }
+ return singleton;
+ }
+
+ @Override
+ public void init() throws Exception {
+ IdeFacade.singleton = this;
+ super.init();
+ }
+
+ @Override
+ protected String getDefaultObjectName() {
+ return "hawtio:type=IdeFacade";
+ }
+
+ /**
+ * Returns the base directory of the current project
+ */
+ public File getBaseDir() {
+ if (baseDir == null) {
+ baseDir = new File(System.getProperty("basedir", "."));
+ }
+ return baseDir;
+ }
+
+ public void setBaseDir(File baseDir) {
+ this.baseDir = baseDir;
+ }
+
+ /**
+ * Given a class name and a file name, try to find the absolute file name of the
+ * source file on the users machine or null if it cannot be found
+ */
+ @Override
+ public String findClassAbsoluteFileName(String fileName, String className, List sourceRoots) {
+ // usually the fileName is just the name of the file without any package information
+ // so lets turn the package name into a path
+ int lastIdx = className.lastIndexOf('.');
+ if (lastIdx > 0 && !(fileName.contains("/") || fileName.contains(File.separator))) {
+ String packagePath = className.substring(0, lastIdx).replace('.', File.separatorChar);
+ fileName = packagePath + File.separator + fileName;
+ }
+ File baseDir = getBaseDir();
+ String answer = findInSourceFolders(baseDir, fileName);
+ if (answer == null && sourceRoots != null) {
+ for (String sourceRoot : sourceRoots) {
+ answer = findInSourceFolders(new File(sourceRoot), fileName);
+ if (answer != null) break;
+ }
+ }
+ return answer;
+ }
+
+ /**
+ * Searches in this directory and in the source directories in src/main/* and src/test/* for the given file name path
+ *
+ * @return the absolute file or null
+ */
+ protected String findInSourceFolders(File baseDir, String fileName) {
+ String answer = findInFolder(baseDir, fileName);
+ if (answer == null && baseDir.exists()) {
+ answer = findInChildFolders(new File(baseDir, "src/main"), fileName);
+ if (answer == null) {
+ answer = findInChildFolders(new File(baseDir, "src/test"), fileName);
+ }
+ }
+ return answer;
+ }
+
+ protected String findInChildFolders(File dir, String fileName) {
+ String answer = findInFolder(dir, fileName);
+ if (answer == null && isDirectory(dir)) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ answer = findInFolder(file, fileName);
+ if (answer != null) break;
+ }
+ }
+ }
+ return answer;
+ }
+
+ protected String findInFolder(File dir, String relativeName) {
+ if (isDirectory(dir)) {
+ File file =new File(dir, relativeName);
+ if (file.exists() && file.isFile()) {
+ return file.getAbsolutePath();
+ }
+ }
+ return null;
+ }
+
+ private boolean isDirectory(File dir) {
+ return dir.exists() && dir.isDirectory();
+ }
+
+ /**
+ * Uses Intellij's XmlRPC mechanism to open and navigate to a file
+ */
+ @Override
+ public String ideaOpenAndNavigate(String fileName, int line, int column) throws Exception {
+ if (line < 0) line = 0;
+ if (column < 0) column = 0;
+ String xml = "\n" +
+ "\n" +
+ " fileOpener.openAndNavigate \n" +
+ " \n" +
+ " " + fileName + " \n" +
+ " " + line + " \n" +
+ " " + column + " \n" +
+ " \n" +
+ " \n";
+
+ return ideaXmlRpc(xml);
+ }
+
+ @Override
+ public String ideaOpen(String fileName) throws Exception {
+ String xml = "\n" +
+ "\n" +
+ " fileOpener.open \n" +
+ " \n" +
+ " " + fileName + " \n" +
+ " \n" +
+ " \n";
+
+ return ideaXmlRpc(xml);
+ }
+
+ protected String ideaXmlRpc(String xml) throws IOException {
+ String charset = "UTF-8";
+
+ HttpURLConnection connection = (HttpURLConnection) new URL("http://localhost:63342").openConnection();
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("accept-charset", charset);
+ connection.setRequestProperty("Content-Type", "text/xml");
+ byte[] bytes = xml.getBytes();
+ connection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
+
+ OutputStream os = null;
+ OutputStreamWriter writer = null;
+ try {
+ os = connection.getOutputStream();
+ os.write(bytes);
+ return IOHelper.readFully(new BufferedReader(new InputStreamReader(connection.getInputStream())));
+ } finally {
+ if (os != null) {
+ try {
+ os.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/java/io/hawt/ide/IdeFacadeMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/java/io/hawt/ide/IdeFacadeMBean.java"
new file mode 100755
index 0000000..cf5d1de
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/java/io/hawt/ide/IdeFacadeMBean.java"
@@ -0,0 +1,25 @@
+package io.hawt.ide;
+
+import java.util.List;
+
+/**
+ * The JMX MBean interface for working with IDEs
+ */
+public interface IdeFacadeMBean {
+
+ /**
+ * Given a class name and a file name, try to find the absolute file name of the
+ * source file on the users machine or null if it cannot be found
+ */
+ String findClassAbsoluteFileName(String fileName, String className, List sourceRoots);
+
+ /**
+ * Open an absolute file name in IDEA and navigate to the position in the file
+ */
+ String ideaOpenAndNavigate(String absoluteFileName, int line, int column) throws Exception;
+
+ /**
+ * Open an absolute file name in IDEA
+ */
+ String ideaOpen(String absoluteFileName) throws Exception;
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/resources/OSGI-INF/blueprint/blueprint.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/resources/OSGI-INF/blueprint/blueprint.xml"
new file mode 100755
index 0000000..af6b16e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/main/resources/OSGI-INF/blueprint/blueprint.xml"
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/test/java/io/hawt/ide/IdeFacadeTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/test/java/io/hawt/ide/IdeFacadeTest.java"
new file mode 100755
index 0000000..7008a9d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/test/java/io/hawt/ide/IdeFacadeTest.java"
@@ -0,0 +1,47 @@
+package io.hawt.ide;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+
+public class IdeFacadeTest {
+ IdeFacade facade = new IdeFacade();
+
+ @Before
+ public void init() throws Exception {
+ facade.init();
+ }
+
+ @After
+ public void destroy() throws Exception {
+ facade.destroy();
+ }
+
+ @Test
+ public void testFindsFileInProject() throws Exception {
+ String absoluteFile = assertFindSampleFileName();
+ System.out.println("Found absolute file: " + absoluteFile);
+ }
+
+ //@Test
+ @Ignore
+ public void testOpenInIDEA() throws Exception {
+ String fileName = assertFindSampleFileName();
+ //assertOperation("ideaOpen", facade.ideaOpen(fileName));
+ assertOperation("ideaOpenAndNavigate", facade.ideaOpenAndNavigate(fileName, 17, 5));
+ }
+
+ protected String assertFindSampleFileName() {
+ String absoluteFile = facade.findClassAbsoluteFileName("IdeFacade.java", "io.hawt.ide.IdeFacade", null);
+ assertNotNull("Should have found an absolute file", absoluteFile);
+ return absoluteFile;
+ }
+
+ protected void assertOperation(String message, String result) {
+ System.out.println("Invoked " + message + " with result " + result);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..70f6cb4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-ide/src/test/resources/log4j.properties"
@@ -0,0 +1,18 @@
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, stdout, out
+
+#log4j.logger.io.hawt.introspect=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/test.log
+log4j.appender.out.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/pom.xml"
new file mode 100755
index 0000000..0b01637
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/pom.xml"
@@ -0,0 +1,87 @@
+
+
+
+ project
+ io.hawt
+ 2.5.0
+
+ 4.0.0
+
+ hawtio-local-jvm-mbean
+ jar
+ ${project.artifactId}
+ hawtio :: ${project.artifactId}
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+ provided
+
+
+
+ org.jolokia
+ jolokia-jvm
+ ${jolokia-version}
+ agent
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ test
+
+
+
+
+
+
+
+ SkipTestsOnWindows
+
+
+
+ Windows
+
+
+
+
+
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
+ pre-java9
+
+
+ com.sun
+ tools
+ 1.6.0
+ system
+ ${java.home}/../lib/tools.jar
+
+
+
+
+ ${java.home}/../lib/tools.jar
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/JVMList.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/JVMList.java"
new file mode 100755
index 0000000..d5be072
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/JVMList.java"
@@ -0,0 +1,287 @@
+package io.hawt.jvm.local;
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import org.jolokia.jvmagent.JvmAgent;
+import org.jolokia.jvmagent.client.command.CommandDispatcher;
+import org.jolokia.jvmagent.client.util.OptionsAndArgs;
+import org.jolokia.jvmagent.client.util.VirtualMachineHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JVMList implements JVMListMBean {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(JVMList.class);
+
+ private MBeanServer mBeanServer;
+ private ObjectName objectName;
+
+ protected static final Map VM_ALIAS_MAP = new HashMap<>();
+ protected static final Map VM_ALIAS_OVERRIDE_MAP = new HashMap<>();
+
+ static {
+ VM_ALIAS_MAP.put("hawtio-app", "hawtio");
+
+ VM_ALIAS_MAP.put("com.intellij.idea.Main", "IntelliJ IDEA");
+ VM_ALIAS_MAP.put("com.intellij.rt.execution.application.AppMain", "IntelliJ IDEA");
+ VM_ALIAS_MAP.put("org.jetbrains.idea.maven.server.RemoteMavenServer", "IntelliJ IDEA");
+ VM_ALIAS_MAP.put("idea maven server", "IntelliJ IDEA");
+ VM_ALIAS_MAP.put("IntelliJ IDEA", "IntelliJ IDEA");
+
+ VM_ALIAS_MAP.put("org.apache.karaf.main.Main", "Apache Karaf");
+ VM_ALIAS_MAP.put("activemq.jar start", "Apache ActiveMQ");
+
+ VM_ALIAS_MAP.put("org.apache.catalina", "Apache Tomcat");
+
+ VM_ALIAS_MAP.put("jetty", "Jetty");
+
+ VM_ALIAS_MAP.put("org.eclipse.equinox.launcher.Main", "Eclipse Equinox");
+
+ VM_ALIAS_MAP.put("scala.tools.nsc.MainGenericRunner", "Scala REPL");
+
+ VM_ALIAS_MAP.put("org.codehaus.groovy.tools.shell.Main", "Groovy Shell");
+ VM_ALIAS_MAP.put("org.codehaus.groovy.tools.GroovyStarter", "Groovy Starter");
+
+ VM_ALIAS_MAP.put("jboss-eap-6.1/jboss-modules.jar", "JBoss EAP 6");
+ VM_ALIAS_MAP.put("wildfly", "WildFly");
+
+ VM_ALIAS_MAP.put("target/surefire", "Maven Surefire Test");
+
+ VM_ALIAS_MAP.put("org.apache.camel:camel-maven-plugin:run", "Apache Camel");
+ VM_ALIAS_MAP.put("camel:run", "Apache Camel");
+
+ VM_ALIAS_MAP.put("org.codehaus.plexus.classworlds.launcher.Launcher spring-boot:run", "Spring Boot");
+ VM_ALIAS_MAP.put("org.springframework.boot.loader.JarLauncher shell", "Spring Boot Shell");
+ VM_ALIAS_MAP.put("org.jboss.forge.bootstrap.Bootstrap", "JBoss Forge Shell");
+
+ VM_ALIAS_OVERRIDE_MAP.put("${zk:root/http}/jolokia", "Fabric8");
+ }
+
+ public JVMList() {
+ }
+
+ public void init() {
+ LOG.debug("Registering JVM discovery MBean: hawtio:type=JVMList");
+
+ try {
+ try {
+ // let's just hit any errors we're going to hit before even creating the mbean
+ listLocalJVMs();
+ } catch (LinkageError e) {
+ // Some JVM's don't support com.sun.tools.attach.VirtualMachine
+ LOG.warn(
+ "Local JVM discovery disabled as this JVM cannot access com.sun.tools.attach.VirtualMachine due to: {}",
+ e.getMessage());
+ return;
+ }
+
+ if (objectName == null) {
+ objectName = new ObjectName("hawtio:type=JVMList");
+ }
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ try {
+ mBeanServer.registerMBean(this, objectName);
+ } catch (InstanceAlreadyExistsException iaee) {
+ // Try to remove and re-register
+ LOG.info("Re-registering SchemaLookup MBean");
+ mBeanServer.unregisterMBean(objectName);
+ mBeanServer.registerMBean(this, objectName);
+ }
+ } catch (Exception e) {
+ LOG.warn("Exception during initialization: ", e);
+ throw new RuntimeException(e);
+ }
+
+ LOG.info("Registered JVM discovery MBean: hawtio:type=JVMList");
+ }
+
+ public void destroy() {
+ try {
+ if (objectName != null && mBeanServer != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ } catch (Exception e) {
+ LOG.warn("Exception unregistering mbean: ", e);
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ @Override
+ public List listLocalJVMs() {
+ List rc = new ArrayList<>();
+ try {
+ List processes = VirtualMachine.list();
+ for (VirtualMachineDescriptor process : processes) {
+ VMDescriptorDTO dto = new VMDescriptorDTO(process);
+ dto.setAgentUrl(agentStatus(dto.getId()));
+
+ String alias = getVmAlias(process.displayName(), dto.getAgentUrl());
+ dto.setAlias(alias);
+
+ // provide fine grained url details
+ if (dto.getAgentUrl() != null) {
+ try {
+ URL url = new URL(dto.getAgentUrl());
+ dto.setScheme(url.getProtocol());
+ dto.setHostname(url.getHost());
+ dto.setPort(url.getPort());
+ dto.setPath(url.getPath());
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ rc.add(dto);
+ }
+ } catch (Exception e) {
+ LOG.warn("Failed to get local JVM processes due to: {}", e.getMessage());
+ throw new RuntimeException("Failed to get local JVM processes due to: " + e.getMessage(), e);
+ }
+ return rc;
+ }
+
+ private void doAction(String PID, String action) {
+ OptionsAndArgs options;
+
+ if (action.equals("start")) {
+ options = new OptionsAndArgs(CommandDispatcher.getAvailableCommands(), "--quiet", "--port", allocateFreePort(), action, PID);
+ } else {
+ options = new OptionsAndArgs(CommandDispatcher.getAvailableCommands(), "--quiet", action, PID);
+ }
+
+ // System.out.println("Jar file at : " + options.getJarFilePath());
+
+ VirtualMachineHandler vmHandler = new VirtualMachineHandler(options);
+ CommandDispatcher dispatcher = new CommandDispatcher(options);
+
+ Object vm = null;
+
+ try {
+ vm = vmHandler.attachVirtualMachine();
+ dispatcher.dispatchCommand(vm, vmHandler);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to " + action + " agent in process " + PID, e);
+ } finally {
+ if (vm != null) {
+ try {
+ vmHandler.detachAgent(vm);
+ } catch (Exception e) {
+ // swallow this?
+ }
+ }
+ }
+ }
+
+ private String allocateFreePort() {
+ int port = 8778;
+
+ ServerSocket sock = null;
+
+ try {
+ sock = new ServerSocket(0);
+ port = sock.getLocalPort();
+ } catch (Exception e) {
+ // ignore;
+ } finally {
+ if (sock != null) {
+ try {
+ sock.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ return Integer.toString(port);
+ }
+
+ @Override
+ public void startAgent(String PID) {
+ doAction(PID, "start");
+ }
+
+ @Override
+ public String agentStatus(String PID) {
+ Object vm = null;
+
+ OptionsAndArgs options = new OptionsAndArgs(CommandDispatcher.getAvailableCommands(), "--quiet", "status", PID);
+ VirtualMachineHandler vmHandler = new VirtualMachineHandler(options);
+
+ String agentUrl = null;
+
+ try {
+ vm = vmHandler.attachVirtualMachine();
+ agentUrl = checkAgentUrl(vm);
+ } catch (Exception e) {
+ // maybe log this
+ } finally {
+ try {
+ vmHandler.detachAgent(vm);
+ } catch (Exception e) {
+ // log this
+ }
+ }
+
+ return agentUrl;
+ }
+
+ @Override
+ public String agentVersion(String PID) {
+ return null;
+ }
+
+ @Override
+ public void stopAgent(String PID) {
+ doAction(PID, "stop");
+ }
+
+ static String getVmAlias(String displayName, String agentUrl) {
+ String answer = displayName;
+ for (String key : VM_ALIAS_MAP.keySet()) {
+ if (displayName.contains(key)) {
+ answer = VM_ALIAS_MAP.get(key);
+ break;
+ }
+ }
+ // the agent url may help indicate what the process really is
+ if (agentUrl != null) {
+ for (String key : VM_ALIAS_OVERRIDE_MAP.keySet()) {
+ if (agentUrl.contains(key)) {
+ answer = VM_ALIAS_OVERRIDE_MAP.get(key);
+ break;
+ }
+ }
+ }
+ return answer;
+ }
+
+ // borrowed these from AbstractBaseCommand for now
+ protected String checkAgentUrl(Object pVm) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ Properties systemProperties = getAgentSystemProperties(pVm);
+ return systemProperties.getProperty(JvmAgent.JOLOKIA_AGENT_URL);
+ }
+
+ protected Properties getAgentSystemProperties(Object pVm) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ Class> clazz = pVm.getClass();
+ Method method = clazz.getMethod("getSystemProperties");
+ return (Properties) method.invoke(pVm);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/JVMListMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/JVMListMBean.java"
new file mode 100755
index 0000000..094bb55
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/JVMListMBean.java"
@@ -0,0 +1,17 @@
+package io.hawt.jvm.local;
+
+import java.util.List;
+
+public interface JVMListMBean {
+
+ List listLocalJVMs();
+
+ void startAgent(String PID);
+
+ String agentStatus(String PID);
+
+ String agentVersion(String PID);
+
+ void stopAgent(String PID);
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/VMDescriptorDTO.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/VMDescriptorDTO.java"
new file mode 100755
index 0000000..681739a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/main/java/io/hawt/jvm/local/VMDescriptorDTO.java"
@@ -0,0 +1,85 @@
+package io.hawt.jvm.local;
+
+import com.sun.tools.attach.VirtualMachineDescriptor;
+
+public class VMDescriptorDTO {
+
+ private VirtualMachineDescriptor descriptor;
+ private String alias;
+ private String agentUrl;
+ private int port;
+ private String hostname;
+ private String scheme;
+ private String path;
+
+ public VMDescriptorDTO(VirtualMachineDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ public String getId() {
+ return descriptor.id();
+ }
+
+ public void setAlias(String alias) {
+ this.alias = alias;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public String getDisplayName() {
+ return descriptor.displayName();
+ }
+
+ public String getAgentUrl() {
+ return agentUrl;
+ }
+
+ public void setAgentUrl(String url) {
+ this.agentUrl = url;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ public void setScheme(String scheme) {
+ this.scheme = scheme;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public String toString() {
+ String agentEnabled = "*";
+ if (getAgentUrl() == null) {
+ agentEnabled = " ";
+ }
+ return getId() + " : [" + agentEnabled + "] " + getAlias() + " (" + getDisplayName() + ")";
+ }
+
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/test/java/io/hawt/jvm/local/JVMListTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/test/java/io/hawt/jvm/local/JVMListTest.java"
new file mode 100755
index 0000000..f46ddd2
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/test/java/io/hawt/jvm/local/JVMListTest.java"
@@ -0,0 +1,110 @@
+package io.hawt.jvm.local;
+
+import org.junit.Assert;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.Ignore;
+import org.junit.runners.MethodSorters;
+
+import java.util.List;
+
+/**
+ *
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class JVMListTest {
+
+ public JVMList getJVMList() {
+ JVMList rc = new JVMList();
+ rc.init();
+ return rc;
+ }
+
+ @Test
+ public void test03ListJVMs() {
+ List jvms = getJVMList().listLocalJVMs();
+
+ for (VMDescriptorDTO jvm : jvms) {
+ System.out.println("JVM: " + jvm);
+ }
+ }
+
+ private void sleep() {
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ @Test
+ @Ignore
+ public void test02StopAgent() {
+ JVMList list = getJVMList();
+ List jvms = list.listLocalJVMs();
+ VMDescriptorDTO me = null;
+
+ for (VMDescriptorDTO jvm : jvms) {
+ //System.out.println("JVM: " + jvm);
+ if (jvm.getAlias().equals("Maven Surefire Test")) {
+ me = jvm;
+ }
+ }
+ Assert.assertNotNull(me);
+
+ try {
+ list.stopAgent(me.getId());
+
+ jvms = list.listLocalJVMs();
+
+ for (VMDescriptorDTO jvm : jvms) {
+ if (jvm.getId().equals(me.getId())) {
+ me = jvm;
+ }
+ }
+
+ System.out.println("Agent URL: " + me.getAgentUrl());
+ Assert.assertNull(me.getAgentUrl());
+ } catch (Exception e) {
+ System.out.print("Error stopping agent due " + e.getMessage() + ". This exception is ignored.");
+ // may fail on some servers, so lets ignore for now
+ }
+ }
+
+ @Test
+ @Ignore
+ public void test01StartAgent() {
+ JVMList list = getJVMList();
+ List jvms = list.listLocalJVMs();
+
+ VMDescriptorDTO me = null;
+ for (VMDescriptorDTO jvm : jvms) {
+ //System.out.println("JVM: " + jvm);
+ if (jvm.getAlias().equals("Maven Surefire Test")) {
+ me = jvm;
+ }
+ }
+ Assert.assertNotNull(me);
+
+ try {
+ System.out.println("Starting agent in " + me.getId());
+ list.startAgent(me.getId());
+
+ sleep();
+
+ jvms = list.listLocalJVMs();
+
+ for (VMDescriptorDTO jvm : jvms) {
+ if (jvm.getId().equals(me.getId())) {
+ me = jvm;
+ }
+ }
+
+ System.out.println("Agent URL: " + me.getAgentUrl());
+ Assert.assertNotNull(me.getAgentUrl());
+ } catch (Exception e) {
+ System.out.print("Error starting agent due " + e.getMessage() + ". This exception is ignored.");
+ // may fail on some servers, so lets ignore for now
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..37ae0f8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-local-jvm-mbean/src/test/resources/log4j.properties"
@@ -0,0 +1,14 @@
+log4j.rootLogger=DEBUG, console, file
+
+# Console will only display warnnings
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n
+log4j.appender.console.threshold=INFO
+
+# File appender will contain all info messages
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n
+log4j.appender.file.file=target/console.log
+log4j.appender.file.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/pom.xml"
new file mode 100755
index 0000000..e66e95b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/pom.xml"
@@ -0,0 +1,88 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-log-osgi
+ ${project.artifactId}
+ hawtio :: hawtio-log-osgi
+ bundle
+
+
+
+
+
+
+
+ io.hawt
+ hawtio-log
+ ${project.version}
+
+
+
+
+ org.osgi
+ org.osgi.core
+ 5.0.0
+ provided
+
+
+ org.osgi
+ org.osgi.enterprise
+ 5.0.0
+ provided
+
+
+ org.apache.karaf.log
+ org.apache.karaf.log.core
+ 4.0.4
+ provided
+
+
+ org.ops4j.pax.logging
+ pax-logging-api
+ 1.8.5
+ provided
+
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ ${maven-bundle-plugin-version}
+ true
+
+
+ bundle-manifest
+ process-classes
+
+ manifest
+
+
+
+
+
+ ${project.description}
+ ${project.groupId}.${project.artifactId}
+ io.hawt.log.osgi.Activator
+
+ org.osgi.framework;version="[1.5,2)",
+ org.osgi.framework.wiring;version="[1.0,2)",
+ org.apache.karaf.log.core;version="[3,5)",
+ *
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/Activator.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/Activator.java"
new file mode 100755
index 0000000..837ff13
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/Activator.java"
@@ -0,0 +1,35 @@
+package io.hawt.log.osgi;
+
+import org.apache.karaf.log.core.LogService;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Activator implements BundleActivator {
+
+ private transient Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+ private LogQuery logQuery;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ ServiceReference ref = context.getServiceReference(LogService.class.getName());
+ if (ref != null) {
+ LogService logService = (LogService) context.getService(ref);
+ logQuery = new LogQuery(logService);
+ logQuery.start();
+ } else {
+ LOG.warn("Cannot find OSGi service " + LogService.class.getName() + " to use by hawtio-log to trap into the Karaf logging service");
+ }
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if (logQuery != null) {
+ logQuery.stop();
+ }
+ }
+}
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQuery.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQuery.java"
new file mode 100755
index 0000000..75fe0b2
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQuery.java"
@@ -0,0 +1,87 @@
+package io.hawt.log.osgi;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+import io.hawt.log.LogFilter;
+import io.hawt.log.LogResults;
+import io.hawt.log.support.LogQuerySupport;
+import io.hawt.log.support.Predicate;
+import org.apache.karaf.log.core.LogService;
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An implementation of {@link LogQueryMBean} using the embedded pax appender used by karaf
+ */
+public class LogQuery extends LogQuerySupport implements LogQueryMBean {
+ private transient Logger LOG = LoggerFactory.getLogger(LogQuery.class);
+
+ private final LogService logService;
+
+ public LogQuery(LogService logService) {
+ this.logService = logService;
+ mapper.getSerializationConfig().withPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, Include.ALWAYS));
+ }
+
+ @Override
+ public String getBundleMavenCoordinates(long bundleId) {
+ return MavenCoordinates.getMavenCoordinates(bundleId);
+ }
+
+ @Override
+ public LogResults getLogResults(int count) throws IOException {
+ LogResults events = getLogEventList(count, null);
+ return events;
+ }
+
+ @Override
+ public LogResults queryLogResults(LogFilter filter) {
+ Predicate predicate = Logs.createPredicate(filter);
+ int count = -1;
+ if (filter != null) {
+ count = filter.getCount();
+ }
+ return getLogEventList(count, predicate);
+ }
+
+ public LogResults getLogEventList(int count, Predicate predicate) {
+ LogResults answer = new LogResults();
+ answer.setHost(getHostName());
+
+ long from = Long.MAX_VALUE;
+ long to = Long.MIN_VALUE;
+ if (logService != null) {
+ Iterable iterable = logService.getEvents();
+ if (iterable != null) {
+ int matched = 0;
+ for (PaxLoggingEvent event : iterable) {
+ if (event != null) {
+ long timestamp = event.getTimeStamp();
+ if (timestamp > to) {
+ to = timestamp;
+ }
+ if (timestamp < from) {
+ from = timestamp;
+ }
+ if (predicate == null || predicate.matches(event)) {
+ answer.addEvent(Logs.newInstance(event));
+ matched += 1;
+ if (count > 0 && matched >= count) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ LOG.warn("No Karaf LogService available!");
+ }
+ answer.setFromTimestamp(from);
+ answer.setToTimestamp(to);
+ return answer;
+ }
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQueryCallback.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQueryCallback.java"
new file mode 100755
index 0000000..419a8a0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQueryCallback.java"
@@ -0,0 +1,7 @@
+package io.hawt.log.osgi;
+
+public interface LogQueryCallback {
+
+ T doWithLogQuery(LogQueryMBean mbean) throws Exception;
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQueryMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQueryMBean.java"
new file mode 100755
index 0000000..7694637
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/LogQueryMBean.java"
@@ -0,0 +1,11 @@
+package io.hawt.log.osgi;
+
+import io.hawt.log.support.LogQuerySupportMBean;
+
+/**
+ * An MBean for querying log events which has a serialized API and a simple JSON API to avoid serialization issues
+ */
+public interface LogQueryMBean extends LogQuerySupportMBean {
+
+ String getBundleMavenCoordinates(long bundleId);
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/Logs.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/Logs.java"
new file mode 100755
index 0000000..5981b65
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/Logs.java"
@@ -0,0 +1,159 @@
+package io.hawt.log.osgi;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import io.hawt.log.LogEvent;
+import io.hawt.log.LogFilter;
+import io.hawt.log.support.Objects;
+import io.hawt.log.support.Predicate;
+import org.ops4j.pax.logging.spi.PaxLevel;
+import org.ops4j.pax.logging.spi.PaxLocationInfo;
+import org.ops4j.pax.logging.spi.PaxLoggingEvent;
+
+import static io.hawt.log.osgi.MavenCoordinates.addMavenCoord;
+
+public class Logs {
+
+ public static LogEvent newInstance(PaxLoggingEvent event) {
+ LogEvent answer = new LogEvent();
+ try {
+ answer.setLevel(toString(event.getLevel()));
+ } catch (NoClassDefFoundError error) {
+ // ENTESB-2234, KARAF-3350: Ignore NoClassDefFoundError exceptions
+ // Those exceptions may happen if the underlying pax-logging service
+ // bundle has been refreshed somehow.
+ answer.setLevel("LOG");
+ }
+ answer.setMessage(event.getMessage());
+ answer.setLogger(event.getLoggerName());
+ answer.setTimestamp(new Date(event.getTimeStamp()));
+ answer.setThread(event.getThreadName());
+ answer.setException(addMavenCoord(event.getThrowableStrRep()));
+
+ Map eventProperties = event.getProperties();
+ if (eventProperties != null && eventProperties.size() > 0) {
+ Map properties = new HashMap();
+ Set set = eventProperties.entrySet();
+ for (Map.Entry entry : set) {
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ if (key != null && value != null) {
+ properties.put(toString(key), toString(value));
+ }
+ }
+ addMavenCoord(properties);
+ answer.setProperties(properties);
+ }
+
+ // TODO missing fields...
+ // event.getRenderedMessage()
+ // event.getFQNOfLoggerClass()
+ try {
+ PaxLocationInfo locationInformation = event.getLocationInformation();
+ if (locationInformation != null) {
+ answer.setClassName(locationInformation.getClassName());
+ answer.setFileName(locationInformation.getFileName());
+ answer.setMethodName(locationInformation.getMethodName());
+ answer.setLineNumber(locationInformation.getLineNumber());
+ }
+ } catch (NoClassDefFoundError error) {
+ // ENTESB-2234, KARAF-3350: Ignore NoClassDefFoundError exceptions
+ }
+ return answer;
+ }
+
+ protected static String toString(Object value) {
+ // TODO should we add any custom marshalling for types?
+ return value.toString();
+ }
+
+ public static Predicate createPredicate(final LogFilter filter) {
+ if (filter == null) {
+ return null;
+ }
+ final List> predicates = new ArrayList>();
+
+ final Set levels = filter.getLevelsSet();
+ if (levels.size() > 0) {
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(PaxLoggingEvent event) {
+ PaxLevel level = event.getLevel();
+ return level != null && levels.contains(level.toString());
+ }
+ });
+ }
+ final Long before = filter.getBeforeTimestamp();
+ if (before != null) {
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(PaxLoggingEvent event) {
+ long time = event.getTimeStamp();
+ return time < before;
+ }
+ });
+ }
+ final Long after = filter.getAfterTimestamp();
+ if (after != null) {
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(PaxLoggingEvent event) {
+ long time = event.getTimeStamp();
+ return time > after;
+ }
+ });
+ }
+
+ final String matchesText = filter.getMatchesText();
+ if (matchesText != null && matchesText.length() > 0) {
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(PaxLoggingEvent event) {
+ if (Objects.contains(matchesText,
+ event.getFQNOfLoggerClass(), event.getMessage(),
+ event.getLoggerName(), event.getThreadName())) {
+ return true;
+ }
+ String[] throwableStrRep = event.getThrowableStrRep();
+ if (throwableStrRep != null && Objects.contains(matchesText, throwableStrRep)) {
+ return true;
+ }
+ Map properties = event.getProperties();
+ if (properties != null && Objects.contains(matchesText, properties.toString())) {
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ if (predicates.size() == 0) {
+ return null;
+ } else if (predicates.size() == 1) {
+ return predicates.get(0);
+ } else {
+ return new Predicate() {
+ @Override
+ public String toString() {
+ return "AndPredicate" + predicates;
+ }
+
+ @Override
+ public boolean matches(PaxLoggingEvent event) {
+ for (Predicate predicate : predicates) {
+ if (!predicate.matches(event)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/MavenCoordinates.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/MavenCoordinates.java"
new file mode 100755
index 0000000..f92d02f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log-osgi/src/main/java/io/hawt/log/osgi/MavenCoordinates.java"
@@ -0,0 +1,110 @@
+package io.hawt.log.osgi;
+
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+import static io.hawt.log.support.MavenCoordinates.appendMavenCoordinateFromPomProperties;
+
+public class MavenCoordinates {
+
+ private static Map MAVEN_COORDINATES = new ConcurrentHashMap();
+
+ public static void addMavenCoord(Map properties) {
+ if (properties.get("maven.coordinates") == null) {
+ String mavenCoord = getMavenCoordinates(properties);
+ if (mavenCoord != null && !mavenCoord.isEmpty()) {
+ properties.put("maven.coordinates", mavenCoord);
+ }
+ }
+ }
+
+ public static String[] addMavenCoord(String[] throwable) {
+ if (throwable != null) {
+ String[] newThrowable = new String[throwable.length];
+ for (int i = 0; i < newThrowable.length; i++) {
+ newThrowable[i] = addMavenCoord(throwable[i]);
+ }
+ return newThrowable;
+ }
+ return throwable;
+ }
+
+ private static String addMavenCoord(String line) {
+ if (line.endsWith("]")) {
+ int index = line.lastIndexOf('[');
+ if (index > 0) {
+ String str = line.substring(index + 1, line.length() - 1);
+ index = str.indexOf(':');
+ if (index > 0) {
+ String idStr = str.substring(0, index);
+ String mvn = getMavenCoordinates(idStr);
+ if (mvn != null) {
+ return line + "[" + mvn + "]";
+ }
+ }
+ }
+ }
+ return line;
+ }
+
+ private static String getMavenCoordinates(Map props) {
+ Object id = (props != null) ? props.get("bundle.id") : null;
+ if (id == null) {
+ return null;
+ }
+ return getMavenCoordinates(id.toString());
+ }
+
+ private static String getMavenCoordinates(String bundleIdStr) {
+ long bundleId;
+ try {
+ bundleId = Long.parseLong(bundleIdStr);
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ return getMavenCoordinates(bundleId);
+ }
+
+ public static Bundle getBundle(long bundleId) {
+ Bundle logBundle = FrameworkUtil.getBundle(Logs.class);
+ BundleContext bundleContext = logBundle != null ? logBundle.getBundleContext() : null;
+ Bundle bundle = bundleContext != null ? bundleContext.getBundle(bundleId) : null;
+ return bundle;
+ }
+
+ public static String getMavenCoordinates(long bundleId) {
+ Bundle bundle = getBundle(bundleId);
+ if (bundle == null) {
+ // Not sure why can't we find the bundleId?
+ return null;
+ }
+ String id = Long.toString(bundle.getBundleId()) + ":" + Long.toString(bundle.getLastModified());
+ String maven = MAVEN_COORDINATES.get(id);
+ if (maven == null) {
+ if (bundle.getState() >= Bundle.RESOLVED) {
+ try {
+ Enumeration e = bundle.findEntries("META-INF/maven/", "pom.properties", true);
+ StringBuilder buf = new StringBuilder();
+ while (e != null && e.hasMoreElements()) {
+ URL url = e.nextElement();
+ appendMavenCoordinateFromPomProperties(url.openStream(), buf);
+ }
+ maven = buf.toString();
+ } catch (Throwable t) {
+ // Ignore
+ maven = "";
+ }
+ MAVEN_COORDINATES.put(id, maven);
+ } else {
+ maven = "";
+ }
+ }
+ return maven;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/pom.xml"
new file mode 100755
index 0000000..3ea16fa
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/pom.xml"
@@ -0,0 +1,81 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-log
+ ${project.artifactId}
+ hawtio :: hawtio-log
+ bundle
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${jackson-version}
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson-version}
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson-version}
+
+
+
+
+ log4j
+ log4j
+ ${log4j-version}
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ ${maven-bundle-plugin-version}
+ true
+
+
+ ${project.description}
+ ${project.groupId}.${project.artifactId}
+
+ com.fasterxml.jackson.annotation;version="${jackson-version-range}",
+ com.fasterxml.jackson.databind;version="${jackson-version-range}",
+ *
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogEvent.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogEvent.java"
new file mode 100755
index 0000000..4dcbd49
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogEvent.java"
@@ -0,0 +1,226 @@
+package io.hawt.log;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import io.hawt.log.support.Objects;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class LogEvent implements Comparable, Serializable {
+ private static final long serialVersionUID = 1L;
+ private static String defaultContainerName;
+
+ private String host;
+ private Long seq;
+ private Date timestamp;
+ private String level;
+ private String logger;
+ private String thread;
+ private String message;
+ private String[] exception;
+ private Map properties;
+ private String className;
+ private String fileName;
+ private String methodName;
+ private String containerName;
+ private String lineNumber;
+
+ static {
+ setDefaultContainerName(System.getProperty("runtime.id"));
+ }
+
+ public static LogEvent toLogEvent(Object element) {
+ if (element instanceof LogEvent) {
+ return (LogEvent) element;
+ }
+ return null;
+ }
+
+ public LogEvent() {
+ this.containerName = getDefaultContainerName();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LogEvent logEvent = (LogEvent) o;
+
+ if (host != null ? !host.equals(logEvent.host) : logEvent.host != null) return false;
+ if (containerName != null ? !containerName.equals(logEvent.containerName) : logEvent.containerName != null) return false;
+ if (logger != null ? !logger.equals(logEvent.logger) : logEvent.logger != null) return false;
+ if (message != null ? !message.equals(logEvent.message) : logEvent.message != null) return false;
+ if (seq != null ? !seq.equals(logEvent.seq) : logEvent.seq != null) return false;
+ if (thread != null ? !thread.equals(logEvent.thread) : logEvent.thread != null) return false;
+ if (timestamp != null ? !timestamp.equals(logEvent.timestamp) : logEvent.timestamp != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int compareTo(LogEvent that) {
+ // use reverse order for timestamp and seq
+ int answer = Objects.compare(this.timestamp, that.timestamp);
+ if (answer == 0) {
+ answer = Objects.compare(this.seq, that.seq);
+ if (answer == 0) {
+ answer = Objects.compare(this.host, that.host);
+ if (answer == 0) {
+ answer = Objects.compare(this.containerName, that.containerName);
+ if (answer == 0) {
+ answer = Objects.compare(this.thread, that.thread);
+ if (answer == 0) {
+ answer = Objects.compare(this.logger, that.logger);
+ if (answer == 0) {
+ answer = Objects.compare(this.message, that.message);
+ }
+ }
+ }
+ }
+ }
+ }
+ return answer;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = host != null ? host.hashCode() : 0;
+ result = 31 * result + (containerName != null ? containerName.hashCode() : 0);
+ result = 31 * result + (seq != null ? seq.hashCode() : 0);
+ result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
+ result = 31 * result + (logger != null ? logger.hashCode() : 0);
+ result = 31 * result + (thread != null ? thread.hashCode() : 0);
+ result = 31 * result + (message != null ? message.hashCode() : 0);
+ return result;
+ }
+
+ /**
+ * A simple concise toString() for debugging purposes
+ */
+ public String toString() {
+ return "[" + getLevel() + "] " + getMessage();
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public String getContainerName() {
+ return containerName;
+ }
+
+ public void setContainerName(String containerName) {
+ this.containerName = containerName;
+ }
+
+ public Long getSeq() {
+ return seq;
+ }
+
+ public void setSeq(Long seq) {
+ this.seq = seq;
+ }
+
+ public Date getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Date timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getLevel() {
+ return level;
+ }
+
+ public void setLevel(String level) {
+ this.level = level;
+ }
+
+ public String getLogger() {
+ return logger;
+ }
+
+ public void setLogger(String logger) {
+ this.logger = logger;
+ }
+
+ public String getThread() {
+ return thread;
+ }
+
+ public void setThread(String thread) {
+ this.thread = thread;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+ public String[] getException() {
+ return exception;
+ }
+
+ public void setException(String[] exception) {
+ this.exception = exception;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public String getLineNumber() {
+ return lineNumber;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public void setLineNumber(String lineNumber) {
+ this.lineNumber = lineNumber;
+ }
+
+ public static String getDefaultContainerName() {
+ return defaultContainerName;
+ }
+
+ public static void setDefaultContainerName(String defaultContainerName) {
+ LogEvent.defaultContainerName = defaultContainerName;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogFilter.java"
new file mode 100755
index 0000000..dbfde78
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogFilter.java"
@@ -0,0 +1,76 @@
+package io.hawt.log;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class LogFilter implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private int count;
+ private String[] levels;
+ private String matchesText;
+ private Long beforeTimestamp;
+ private Long afterTimestamp;
+
+ @Override
+ public String toString() {
+ return "LogFilter{" +
+ "count=" + count +
+ ", afterTimestamp=" + afterTimestamp +
+ ", matchesText='" + matchesText + '\'' +
+ '}';
+ }
+
+ public Set getLevelsSet() {
+ if (levels == null || levels.length == 0) {
+ return Collections.EMPTY_SET;
+ }
+ return new HashSet(Arrays.asList(levels));
+ }
+
+
+ // Properties
+ //-------------------------------------------------------------------------
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String[] getLevels() {
+ return levels;
+ }
+
+ public void setLevels(String[] levels) {
+ this.levels = levels;
+ }
+
+ public String getMatchesText() {
+ return matchesText;
+ }
+
+ public void setMatchesText(String matchesText) {
+ this.matchesText = matchesText;
+ }
+
+ public Long getBeforeTimestamp() {
+ return beforeTimestamp;
+ }
+
+ public Long getAfterTimestamp() {
+ return afterTimestamp;
+ }
+
+ public void setAfterTimestamp(Long afterTimestamp) {
+ this.afterTimestamp = afterTimestamp;
+ }
+
+ public void setBeforeTimestamp(Long beforeTimestamp) {
+ this.beforeTimestamp = beforeTimestamp;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogResults.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogResults.java"
new file mode 100755
index 0000000..d01e4ed
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/LogResults.java"
@@ -0,0 +1,55 @@
+package io.hawt.log;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Results of a query which also records the first and last timestamp searched
+ */
+public class LogResults implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private List events;
+ private Long fromTimestamp;
+ private Long toTimestamp;
+ private String host;
+
+ public void addEvent(LogEvent event) {
+ if (events == null) {
+ events = new ArrayList();
+ }
+ events.add(event);
+ }
+
+ public List getEvents() {
+ return events;
+ }
+
+ public void setEvents(List events) {
+ this.events = events;
+ }
+
+ public Long getFromTimestamp() {
+ return fromTimestamp;
+ }
+
+ public void setFromTimestamp(Long fromTimestamp) {
+ this.fromTimestamp = fromTimestamp;
+ }
+
+ public Long getToTimestamp() {
+ return toTimestamp;
+ }
+
+ public void setToTimestamp(Long toTimestamp) {
+ this.toTimestamp = toTimestamp;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/Log4jLogQuery.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/Log4jLogQuery.java"
new file mode 100755
index 0000000..aa45742
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/Log4jLogQuery.java"
@@ -0,0 +1,398 @@
+package io.hawt.log.log4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import io.hawt.log.LogEvent;
+import io.hawt.log.LogFilter;
+import io.hawt.log.LogResults;
+import io.hawt.log.support.LogQuerySupport;
+import io.hawt.log.support.LruList;
+import io.hawt.log.support.Predicate;
+import org.apache.log4j.Appender;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Category;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static io.hawt.log.support.Objects.contains;
+
+// TODO: re-enable mvn resolver (requires code to be ported from fabric8 v1)
+
+/**
+ * A log4j adapter for LogQueryMBean
+ */
+public class Log4jLogQuery extends LogQuerySupport implements Log4jLogQueryMBean {
+ private static final transient Logger LOG = LoggerFactory.getLogger(Log4jLogQuery.class);
+
+ private int size = 2000;
+ private LruList events;
+ private boolean addMavenCoordinates = false;
+// private AetherBasedResolver resolver;
+// private MavenConfigurationImpl config;
+ private Properties properties = new Properties();
+ private final Appender appender = new AppenderSkeleton() {
+ protected void append(LoggingEvent loggingEvent) {
+ logMessage(loggingEvent);
+ }
+
+ public void close() {
+ }
+
+ public boolean requiresLayout() {
+ return true;
+ }
+ };
+
+
+ public void start() {
+ super.start();
+
+ reconnectAppender();
+ }
+
+ @Override
+ public void reconnectAppender() {
+ ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
+
+ boolean added = false;
+ if (loggerFactory instanceof AppenderAttachable) {
+ AppenderAttachable appenderAttachable = (AppenderAttachable) loggerFactory;
+ appender.setName("LogQuery");
+ appenderAttachable.addAppender(appender);
+ LOG.info("Connected to Log4j appender to trap logs with hawtio log plugin");
+ added = true;
+ }
+
+ org.apache.log4j.Logger root = LogManager.getRootLogger();
+ if (root != null) {
+ appender.setName("LogQuery");
+ root.addAppender(appender);
+ LOG.info("Connected to Log4j appender to trap logs with hawtio log plugin");
+ added = true;
+ }
+
+ if (!added) {
+ LOG.warn("No ILoggerFactory or RootLogger found so cannot attach hatwio log appender!");
+ }
+ }
+
+ public void stop() {
+ super.stop();
+ }
+
+ public LogResults getLogResults(int maxCount) throws IOException {
+ return filterLogResults(null, maxCount);
+ }
+
+ public LogResults queryLogResults(LogFilter filter) {
+ Predicate predicate = createPredicate(filter);
+ int maxCount = -1;
+ if (filter != null) {
+ maxCount = filter.getCount();
+ }
+ return filterLogResults(predicate, maxCount);
+ }
+
+ private Predicate createPredicate(LogFilter filter) {
+ if (filter == null) {
+ return null;
+ }
+ final List> predicates = new ArrayList>();
+
+ final Set levels = filter.getLevelsSet();
+ if (levels.size() > 0) {
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(LogEvent event) {
+ String level = event.getLevel();
+ return level != null && levels.contains(level.toString());
+ }
+ });
+ }
+ final Long before = filter.getBeforeTimestamp();
+ if (before != null) {
+ final Date date = new Date(before);
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(LogEvent event) {
+ Date time = event.getTimestamp();
+ return time != null && time.before(date);
+ }
+ });
+ }
+ final Long after = filter.getAfterTimestamp();
+ if (after != null) {
+ final Date date = new Date(after);
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(LogEvent event) {
+ Date time = event.getTimestamp();
+ return time != null && time.after(date);
+ }
+ });
+ }
+
+ final String matchesText = filter.getMatchesText();
+ if (matchesText != null && matchesText.length() > 0) {
+ predicates.add(new Predicate() {
+ @Override
+ public boolean matches(LogEvent event) {
+ if (contains(matchesText, event.getClassName(), event.getMessage(), event.getLogger(), event.getThread())) {
+ return true;
+ }
+ String[] throwableStrRep = event.getException();
+ if (throwableStrRep != null && contains(matchesText, throwableStrRep)) {
+ return true;
+ }
+ Map properties = event.getProperties();
+ if (properties != null && contains(matchesText, properties.toString())) {
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ if (predicates.size() == 0) {
+ return null;
+ } else if (predicates.size() == 1) {
+ return predicates.get(0);
+ } else {
+ return new Predicate() {
+ @Override
+ public String toString() {
+ return "AndPredicate" + predicates;
+ }
+
+ @Override
+ public boolean matches(LogEvent event) {
+ for (Predicate predicate : predicates) {
+ if (!predicate.matches(event)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+ }
+ }
+
+ protected LogResults filterLogResults(Predicate predicate, int maxCount) {
+ int matched = 0;
+ long from = Long.MAX_VALUE;
+ long to = Long.MIN_VALUE;
+ List list = new ArrayList();
+ Iterable elements = getEvents().getElements();
+ for (LoggingEvent element : elements) {
+ LogEvent logEvent = toLogEvent(element);
+ long timestamp = element.getTimeStamp();
+ if (timestamp > to) {
+ to = timestamp;
+ }
+ if (timestamp < from) {
+ from = timestamp;
+ }
+ if (logEvent != null) {
+ if (predicate == null || predicate.matches(logEvent)) {
+ list.add(logEvent);
+ matched += 1;
+ if (maxCount > 0 && matched >= maxCount) {
+ break;
+ }
+ }
+ }
+ }
+ LogResults results = new LogResults();
+ results.setEvents(list);
+ if (from < Long.MAX_VALUE) {
+ results.setFromTimestamp(from);
+ }
+ if (to > Long.MIN_VALUE) {
+ results.setToTimestamp(to);
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Requested " + maxCount + " logging items. returning "
+ + results.getEvents().size() + " event(s) from a possible " + getEvents().size());
+
+ }
+ return results;
+ }
+
+ protected LogEvent toLogEvent(LoggingEvent element) {
+ LogEvent answer = new LogEvent();
+ answer.setClassName(element.getFQNOfLoggerClass());
+ // TODO
+ //answer.setContainerName(element.get);
+ ThrowableInformation throwableInformation = element.getThrowableInformation();
+ if (throwableInformation != null) {
+ ThrowableFormatter renderer = new ThrowableFormatter();
+ String[] stack = renderer.doRender(throwableInformation.getThrowable());
+ if (stack == null) {
+ stack = element.getThrowableStrRep();
+ }
+ answer.setException(stack);
+ }
+ LocationInfo locationInformation = element.getLocationInformation();
+ if (locationInformation != null) {
+ answer.setFileName(locationInformation.getFileName());
+ answer.setClassName(locationInformation.getClassName());
+ answer.setMethodName(locationInformation.getMethodName());
+ answer.setLineNumber(locationInformation.getLineNumber());
+ }
+ Level level = element.getLevel();
+ if (level != null) {
+ answer.setLevel(level.toString());
+ }
+ // TODO
+ answer.setLogger(element.getLoggerName());
+ Category logger = element.getLogger();
+ Object message = element.getMessage();
+ if (message != null) {
+ // TODO marshal differently?
+ answer.setMessage(message.toString());
+ }
+ answer.setProperties(element.getProperties());
+ // TODO
+ answer.setSeq(element.getTimeStamp());
+ answer.setTimestamp(new Date(element.getTimeStamp()));
+ answer.setThread(element.getThreadName());
+ answer.setHost(getHostName());
+ return answer;
+ }
+
+ protected String filterLogEvents(LogFilter filter) throws IOException {
+ // TODO
+ return null;
+ }
+
+
+ protected void appendMavenCoordinates(LoggingEvent loggingEvent) {
+ LocationInfo information = loggingEvent.getLocationInformation();
+ if (information != null) {
+ String coordinates = MavenCoordHelper.getMavenCoordinates(information.getClassName());
+ if (coordinates != null) {
+ loggingEvent.setProperty("maven.coordinates", coordinates);
+ }
+ }
+ }
+
+ protected String loadCoords(String coords, String filePath, String classifier) throws IOException {
+ String[] split = coords.split("/");
+ if (split != null && split.length > 2) {
+ String groupId = split[0];
+ String artifactId = split[1];
+ String version = split[2];
+ /*if (resolver == null) {
+ Properties defaultProperties = getDefaultProperties();
+ Properties systemProperties = System.getProperties();
+ if (config == null) {
+ Properties combined = new Properties();
+ combined.putAll(defaultProperties);
+ combined.putAll(systemProperties);
+ if (properties != null) {
+ combined.putAll(properties);
+ }
+ config = new MavenConfigurationImpl(new PropertiesPropertyResolver(combined), ServiceConstants.PID);
+ }
+ resolver = new AetherBasedResolver(config);
+ }
+ File file = resolver.resolveFile(groupId, artifactId, classifier, "jar", version);
+ if (file.exists() && file.isFile()) {
+ if (isRoot(filePath)) {
+ return jarIndex(file);
+ }
+ String fileUri = file.toURI().toString();
+ URL url = new URL("jar:" + fileUri + "!" + filePath);
+ return loadString(url);
+ } */
+ }
+ return null;
+ }
+
+ protected Properties getDefaultProperties() {
+ Properties defaultProperties = new Properties();
+ defaultProperties.setProperty("org.ops4j.pax.url.mvn.repositories",
+ "http://repo1.maven.org/maven2@id=maven.central.repo, " +
+ "https://repo.fusesource.com/nexus/content/repositories/releases@id=fusesource.release.repo, " +
+ "https://repo.fusesource.com/nexus/content/groups/ea@id=fusesource.ea.repo, " +
+ "http://svn.apache.org/repos/asf/servicemix/m2-repo@id=servicemix.repo, " +
+ "http://repository.springsource.com/maven/bundles/release@id=springsource.release.repo, " +
+ "http://repository.springsource.com/maven/bundles/external@id=springsource.external.repo, " +
+ "https://oss.sonatype.org/content/groups/scala-tools@id=scala.repo");
+ return defaultProperties;
+ }
+
+ // Properties
+ //-------------------------------------------------------------------------
+ public LruList getEvents() {
+ if (events == null) {
+ events = new LruList(LoggingEvent.class, getSize());
+ }
+ return events;
+ }
+
+ public void setEvents(LruList events) {
+ this.events = events;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+
+ public boolean isAddMavenCoordinates() {
+ return addMavenCoordinates;
+ }
+
+ public void setAddMavenCoordinates(boolean addMavenCoordinates) {
+ this.addMavenCoordinates = addMavenCoordinates;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+// public MavenConfigurationImpl getConfig() {
+// return config;
+// }
+//
+// public void setConfig(MavenConfigurationImpl config) {
+// this.config = config;
+// }
+//
+// public AetherBasedResolver getResolver() {
+// return resolver;
+// }
+//
+// public void setResolver(AetherBasedResolver resolver) {
+// this.resolver = resolver;
+// }
+
+ @Override
+ public void logMessage(LoggingEvent record) {
+ if (addMavenCoordinates) {
+ appendMavenCoordinates(record);
+ }
+ getEvents().add(record);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/Log4jLogQueryMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/Log4jLogQueryMBean.java"
new file mode 100755
index 0000000..eaf884e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/Log4jLogQueryMBean.java"
@@ -0,0 +1,19 @@
+package io.hawt.log.log4j;
+
+import io.hawt.log.support.LogQuerySupportMBean;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * The MBean operations for {@link Log4jLogQuery}
+ */
+public interface Log4jLogQueryMBean extends LogQuerySupportMBean {
+
+ /**
+ * Provides a hook you can call if the underlying log4j
+ * configuration is reloaded so that you can force the appender
+ * to get re-registered.
+ */
+ void reconnectAppender();
+
+ public void logMessage(LoggingEvent record);
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/MavenCoordHelper.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/MavenCoordHelper.java"
new file mode 100755
index 0000000..56b9666
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/MavenCoordHelper.java"
@@ -0,0 +1,116 @@
+package io.hawt.log.log4j;
+
+import io.hawt.log.support.MavenCoordinates;
+import io.hawt.log.support.Objects;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A helper class for finding the maven coordinates
+ */
+public class MavenCoordHelper {
+ private static final transient Logger LOG = LoggerFactory.getLogger(MavenCoordHelper.class);
+ // TODO need to have one of these per class loader ideally
+ private static Map classToMavenCoordMap = new ConcurrentHashMap();
+
+ public static String getMavenCoordinates(String className) {
+ String coordinates = null;
+ if (!Objects.isBlank(className)) {
+ coordinates = classToMavenCoordMap.get(className);
+ if (coordinates == null) {
+ try {
+ Class cls = findClass(className);
+ coordinates = getMavenCoordinates(cls);
+ } catch (Throwable t) {
+ LOG.debug("Can't find maven coordinate for " + className);
+ }
+ }
+ }
+ return coordinates;
+ }
+
+ public static String getMavenCoordinates(Class cls) throws IOException {
+ StringBuilder buffer = new StringBuilder();
+ try {
+ CodeSource source = cls.getProtectionDomain().getCodeSource();
+ if (source != null) {
+ URL locationURL = source.getLocation();
+ if (locationURL != null) {
+ // lets try find the pom.properties file...
+
+ //
+ // if a file: URL
+ //
+ if ("file".equals(locationURL.getProtocol())) {
+ String path = locationURL.getPath();
+ if (path != null) {
+ File file = new File(path);
+ if (file.exists() && !file.isDirectory()) {
+ String coordinates = MavenCoordinates.mavenCoordinatesFromJarFile(file);
+ if (!Objects.isBlank(coordinates)) {
+ return coordinates;
+ }
+ }
+ //
+ // find the last file separator character
+ //
+ int lastSlash = path.lastIndexOf('/');
+ int lastBack = path.lastIndexOf(File.separatorChar);
+ if (lastBack > lastSlash) {
+ lastSlash = lastBack;
+ }
+ //
+ // if no separator or ends with separator (a directory)
+ // then output the URL, otherwise just the file name.
+ //
+ if (lastSlash <= 0 || lastSlash == path.length() - 1) {
+ buffer.append(locationURL);
+ } else {
+ buffer.append(path.substring(lastSlash + 1));
+ }
+ }
+ } else {
+ buffer.append(locationURL);
+ }
+ }
+ }
+ } catch (SecurityException ex) {
+ }
+ buffer.append(':');
+ Package pkg = cls.getPackage();
+ if (pkg != null) {
+ String implVersion = pkg.getImplementationVersion();
+ if (implVersion != null) {
+ buffer.append(implVersion);
+ }
+ }
+ return buffer.toString();
+ }
+
+
+ /**
+ * Find class given class name.
+ *
+ * @param className class name, may not be null.
+ * @return class, will not be null.
+ * @throws ClassNotFoundException thrown if class can not be found.
+ */
+ protected static Class findClass(final String className) throws ClassNotFoundException {
+ try {
+ return Thread.currentThread().getContextClassLoader().loadClass(className);
+ } catch (ClassNotFoundException e) {
+ try {
+ return Class.forName(className);
+ } catch (ClassNotFoundException e1) {
+ return MavenCoordHelper.class.getClassLoader().loadClass(className);
+ }
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/ThrowableFormatter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/ThrowableFormatter.java"
new file mode 100755
index 0000000..8a8576c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/log4j/ThrowableFormatter.java"
@@ -0,0 +1,155 @@
+package io.hawt.log.log4j;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.HashMap;
+import java.util.Map;
+
+import io.hawt.log.support.Objects;
+
+/**
+ * Code modified from log4j to format exceptions
+ */
+public class ThrowableFormatter {
+ /**
+ * Throwable.getStackTrace() method.
+ */
+ private Method getStackTraceMethod;
+ /**
+ * StackTraceElement.getClassName() method.
+ */
+ private Method getClassNameMethod;
+
+
+ /**
+ * Construct new instance.
+ */
+ public ThrowableFormatter() {
+ try {
+ Class[] noArgs = null;
+ getStackTraceMethod = Throwable.class.getMethod("getStackTrace", noArgs);
+ Class ste = Class.forName("java.lang.StackTraceElement");
+ getClassNameMethod = ste.getMethod("getClassName", noArgs);
+ } catch (Exception ex) {
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] doRender(final Throwable throwable) {
+ if (getStackTraceMethod != null) {
+ try {
+ Object[] noArgs = null;
+ Object[] elements = (Object[])getStackTraceMethod.invoke(throwable, noArgs);
+ String[] lines = new String[elements.length + 1];
+ lines[0] = throwable.toString();
+ Map classMap = new HashMap();
+ for (int i = 0; i < elements.length; i++) {
+ lines[i + 1] = formatElement(elements[i], classMap);
+ }
+ return lines;
+ } catch (Exception ex) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Format one element from stack trace.
+ *
+ * @param element element, may not be null.
+ * @param classMap map of class name to location.
+ * @return string representation of element.
+ */
+ private String formatElement(final Object element, final Map classMap) {
+ StringBuffer buf = new StringBuffer("\tat ");
+ buf.append(element);
+ try {
+ String className = getClassNameMethod.invoke(element, (Object[])null).toString();
+ Object classDetails = classMap.get(className);
+ if (classDetails != null) {
+ buf.append(classDetails);
+ } else {
+ Class cls = findClass(className);
+ int detailStart = buf.length();
+ buf.append('[');
+ String mavenCoordinates = MavenCoordHelper.getMavenCoordinates(cls);
+ if (!Objects.isBlank(mavenCoordinates)) {
+ buf.append(mavenCoordinates);
+ } else {
+ try {
+ CodeSource source = cls.getProtectionDomain().getCodeSource();
+ if (source != null) {
+ URL locationURL = source.getLocation();
+ if (locationURL != null) {
+ //
+ // if a file: URL
+ //
+ if ("file".equals(locationURL.getProtocol())) {
+ String path = locationURL.getPath();
+ if (path != null) {
+ //
+ // find the last file separator character
+ //
+ int lastSlash = path.lastIndexOf('/');
+ int lastBack = path.lastIndexOf(File.separatorChar);
+ if (lastBack > lastSlash) {
+ lastSlash = lastBack;
+ }
+ //
+ // if no separator or ends with separator (a directory)
+ // then output the URL, otherwise just the file name.
+ //
+ if (lastSlash <= 0 || lastSlash == path.length() - 1) {
+ buf.append(locationURL);
+ } else {
+ buf.append(path.substring(lastSlash + 1));
+ }
+ }
+ } else {
+ buf.append(locationURL);
+ }
+ }
+ }
+ } catch (SecurityException ex) {
+ }
+ buf.append(':');
+ Package pkg = cls.getPackage();
+ if (pkg != null) {
+ String implVersion = pkg.getImplementationVersion();
+ if (implVersion != null) {
+ buf.append(implVersion);
+ }
+ }
+ }
+ buf.append(']');
+ classMap.put(className, buf.substring(detailStart));
+ }
+ } catch (Exception ex) {
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Find class given class name.
+ *
+ * @param className class name, may not be null.
+ * @return class, will not be null.
+ * @throws ClassNotFoundException thrown if class can not be found.
+ */
+ private Class findClass(final String className) throws ClassNotFoundException {
+ try {
+ return Thread.currentThread().getContextClassLoader().loadClass(className);
+ } catch (ClassNotFoundException e) {
+ try {
+ return Class.forName(className);
+ } catch (ClassNotFoundException e1) {
+ return getClass().getClassLoader().loadClass(className);
+ }
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogRequest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogRequest.java"
new file mode 100755
index 0000000..f2f3d56
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogRequest.java"
@@ -0,0 +1,114 @@
+package io.hawt.log.rest;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+public class LogRequest {
+ private long from;
+ private long size;
+ private List> sort;
+ private Map query;
+
+ public static LogRequest newInstance(Long maxLogSeq) {
+ List> s = new ArrayList();
+ s.add(keyValueMap("timestamp", "desc"));
+ s.add(keyValueMap("seq", "desc"));
+
+ Map q = new HashMap();
+ Map constant_score = new HashMap();
+ Map filter = new HashMap();
+
+ q.put("constant_score", constant_score);
+ constant_score.put("filter", filter);
+
+ List listOfTerms = new ArrayList();
+ //listOfTerms.add(createSearchTerm("host", "root"));
+ listOfTerms.add(createSearchTerms("level", "error", "warn", "info"));
+
+ if (maxLogSeq != null) {
+ listOfTerms.add(createSearchRangeGt("seq", maxLogSeq));
+ }
+
+ filter.put("and", listOfTerms);
+
+ return new LogRequest(0, 50, s, q);
+ }
+
+ private static Map keyValueMap(String key, String value) {
+ Map answer = new HashMap();
+ answer.put(key, value);
+ return answer;
+ }
+
+ protected static Map createSearchRangeGt(String name, Object value) {
+ return createSearchRange(name, "gt", value);
+ }
+
+ protected static Map createSearchRange(String name, String compareOperation, Object value) {
+ Map answer = new HashMap();
+ Map range = new HashMap();
+ Map compare = new HashMap();
+ answer.put("range", range);
+ range.put(compareOperation, compare);
+ compare.put(name, value);
+ return answer;
+ }
+
+ protected static Map createSearchTerm(String name, String value) {
+ Map answer = new HashMap();
+ Map term = new HashMap();
+ answer.put("term", term);
+ term.put(name, value);
+ return answer;
+ }
+
+ protected static Map createSearchTerms(String name, String... values) {
+ Map answer = new HashMap();
+ Map term = new HashMap();
+ answer.put("terms", term);
+ term.put(name, new ArrayList(Arrays.asList(values)));
+ return answer;
+ }
+
+ @JsonCreator
+ public LogRequest(long from, long size, List> sort, Map query) {
+ this.from = from;
+ this.size = size;
+ this.sort = sort;
+ this.query = query;
+ }
+ public long getFrom() {
+ return from;
+ }
+ public void setFrom(long from) {
+ this.from = from;
+ }
+ public long getSize() {
+ return size;
+ }
+ public void setSize(long size) {
+ this.size = size;
+ }
+ public List> getSort() {
+ return sort;
+ }
+ public void setSort(List> sort) {
+ this.sort = sort;
+ }
+
+ public Map getQuery() {
+ return query;
+ }
+
+ public void setQuery(Map query) {
+ this.query = query;
+ }
+
+
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponse.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponse.java"
new file mode 100755
index 0000000..936b5ef
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponse.java"
@@ -0,0 +1,25 @@
+package io.hawt.log.rest;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class LogResponse {
+ private LogResponseHits hits;
+
+ @JsonCreator
+ public LogResponse(@JsonProperty("hits") LogResponseHits hits) {
+ this.hits = hits;
+ }
+
+ public LogResponseHits getHits() {
+ return hits;
+ }
+
+ public void setHits(LogResponseHits hits) {
+ this.hits = hits;
+ }
+
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponseHit.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponseHit.java"
new file mode 100755
index 0000000..1a7569e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponseHit.java"
@@ -0,0 +1,24 @@
+package io.hawt.log.rest;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.hawt.log.LogEvent;
+
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class LogResponseHit {
+
+ @JsonProperty("_source")
+ private LogEvent event;
+
+ public LogResponseHit() {
+ }
+
+ public LogEvent getEvent() {
+ return event;
+ }
+
+ public void setEvent(LogEvent event) {
+ this.event = event;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponseHits.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponseHits.java"
new file mode 100755
index 0000000..7f269f3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/rest/LogResponseHits.java"
@@ -0,0 +1,27 @@
+package io.hawt.log.rest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class LogResponseHits {
+ private List hits = new ArrayList();
+
+ @JsonCreator
+ public LogResponseHits(@JsonProperty("hits") List hits) {
+ this.hits = hits;
+ }
+
+ public List getHits() {
+ return hits;
+ }
+
+ public void setHits(List hits) {
+ this.hits = hits;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LogQuerySupport.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LogQuerySupport.java"
new file mode 100755
index 0000000..a6bb84b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LogQuerySupport.java"
@@ -0,0 +1,314 @@
+package io.hawt.log.support;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.hawt.log.LogFilter;
+import io.hawt.log.LogResults;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for any {@link LogQuerySupportMBean} implementation
+ */
+public abstract class LogQuerySupport implements LogQuerySupportMBean {
+ private static final transient Logger LOG = LoggerFactory.getLogger(LogQuerySupport.class);
+
+ protected ObjectMapper mapper = new ObjectMapper();
+ private ObjectName mbeanName;
+ private MBeanServer mbeanServer;
+ private String hostName;
+ private volatile ObjectInstance objectInstance;
+
+ protected LogQuerySupport() {
+ try {
+ hostName = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ LOG.warn("Failed to get host name: " + e, e);
+ }
+ }
+
+ protected static String loadString(URL url) throws IOException {
+ InputStream is = url.openStream();
+ if (is == null) {
+ return null;
+ }
+ try {
+ InputStreamReader reader = new InputStreamReader(is);
+ StringWriter writer = new StringWriter();
+ final char[] buffer = new char[4096];
+ int n;
+ while ( -1 != ( n = reader.read( buffer ) ) )
+ {
+ writer.write( buffer, 0, n );
+ }
+ writer.flush();
+ return writer.toString();
+ } finally {
+ is.close();
+ }
+ }
+
+ /**
+ * Registers the object with JMX
+ */
+ public void start() {
+ MBeanServer server = getMbeanServer();
+ if (server != null) {
+ registerMBeanServer(server);
+ } else {
+ LOG.error("No MBeanServer available so cannot register mbean");
+ }
+ }
+
+ /**
+ * Unregisters the object with JMX
+ */
+ public void stop() {
+ MBeanServer server = getMbeanServer();
+ if (server != null) {
+ unregisterMBeanServer(server);
+ }
+ }
+
+ public LogResults allLogResults() throws IOException {
+ return getLogResults(-1);
+ }
+
+ @Override
+ public LogResults logResultsSince(long time) throws IOException {
+ LogFilter filter = new LogFilter();
+ filter.setAfterTimestamp(time);
+ return queryLogResults(filter);
+ }
+
+ public String getLogEvents(int maxCount) throws IOException {
+ LogResults results = getLogResults(maxCount);
+ return toJSON(results);
+ }
+
+ @Override
+ public String filterLogEvents(String jsonFilter) throws IOException {
+ LogResults results = jsonQueryLogResults(jsonFilter);
+ return toJSON(results);
+ }
+
+ @Override
+ public LogResults jsonQueryLogResults(String jsonFilter) throws IOException {
+ LogFilter filter = jsonToLogFilter(jsonFilter);
+ return queryLogResults(filter);
+ }
+
+ public ObjectName getMbeanName() throws MalformedObjectNameException {
+ if (mbeanName == null) {
+ mbeanName = new ObjectName("hawtio:type=LogQuery");
+ }
+ return mbeanName;
+ }
+
+ public void setMbeanName(ObjectName mbeanName) {
+ this.mbeanName = mbeanName;
+ }
+
+ public MBeanServer getMbeanServer() {
+ if (mbeanServer == null) {
+ mbeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ return mbeanServer;
+ }
+
+ public void setMbeanServer(MBeanServer mbeanServer) {
+ this.mbeanServer = mbeanServer;
+ }
+
+ public String getHostName() {
+ return hostName;
+ }
+
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ }
+
+ public void registerMBeanServer(MBeanServer mbeanServer) {
+ try {
+ ObjectName name = getMbeanName();
+ if (mbeanServer.isRegistered(name)) {
+ LOG.warn("MBean " + name + " is already registered!");
+ } else {
+ objectInstance = mbeanServer.registerMBean(this, name);
+ }
+ } catch (Exception e) {
+ LOG.warn("An error occurred during mbean server registration: " + e, e);
+ }
+ }
+
+ public void unregisterMBeanServer(MBeanServer mbeanServer) {
+ if (mbeanServer != null) {
+ try {
+ ObjectName name = objectInstance != null ? objectInstance.getObjectName() : getMbeanName();
+ if (name != null && mbeanServer.isRegistered(name)) {
+ mbeanServer.unregisterMBean(name);
+ objectInstance = null;
+ }
+ } catch (Exception e) {
+ LOG.warn("An error occurred during mbean server registration: " + e, e);
+ }
+ }
+ }
+
+ protected String toJSON(Object answer) throws IOException {
+ try {
+ StringWriter writer = new StringWriter();
+ mapper.writeValue(writer, answer);
+ return writer.toString();
+ } catch (IOException e) {
+ LOG.warn("Failed to marshal the events: " + e, e);
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ protected LogFilter jsonToLogFilter(String json) throws IOException {
+ if (json == null) {
+ return null;
+ }
+ json = json.trim();
+ if (json.length() == 0 || json.equals("{}")) {
+ return null;
+ }
+ return mapper.readerFor(LogFilter.class).readValue(json);
+ }
+
+ public String getSource(String mavenCoords, String className, String filePath) throws IOException {
+ // the fileName could be just a name and extension so we may have to use the className to make a fully qualified package
+ String classNamePath = null;
+ if (!Objects.isBlank(className)) {
+ classNamePath = className.replace('.', '/') + ".java";
+ }
+ if (Objects.isBlank(filePath)) {
+ filePath = classNamePath;
+ } else {
+ // we may have package in the className but not in the file name
+ if (filePath.lastIndexOf('/') <= 0 && classNamePath != null) {
+ int idx = classNamePath.lastIndexOf('/');
+ if (idx > 0) {
+ filePath = classNamePath.substring(0, idx) + ensureStartsWithSlash(filePath);
+ }
+ }
+ }
+ return getArtifactFile(mavenCoords, filePath, "sources");
+ }
+
+ public String getJavaDoc(String mavenCoordinates, String filePath) throws IOException {
+ return getArtifactFile(mavenCoordinates, filePath, "javadoc");
+ }
+
+ protected String getArtifactFile(String mavenCoords, String filePath, String classifier) throws IOException {
+ filePath = ensureStartsWithSlash(filePath);
+
+ String coords = mavenCoords.replace(':', '/');
+ String[] array = coords.split("\\s+");
+ if (array == null || array.length < 2) {
+ return loadCoords(coords, filePath, classifier);
+ } else {
+ // lets enumerate all values if space separated
+ if (isRoot(filePath)) {
+ StringBuilder buffer = new StringBuilder();
+ for (String coord : array) {
+ try {
+ String text = loadCoords(coord, filePath, classifier);
+ if (text != null) {
+ buffer.append(text);
+ }
+ } catch (IOException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("" + e);
+ }
+ }
+ }
+ return buffer.toString();
+ } else {
+ for (String coord : array) {
+ try {
+ return loadCoords(coord, filePath, classifier);
+ } catch (IOException e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("" + e);
+ }
+ }
+ }
+ return null;
+ }
+ }
+ }
+
+ protected String loadCoords(String coords, String filePath, String classifier) throws IOException {
+ URL url = new URL("jar:mvn:" + coords + "/jar/" + classifier + "!" + filePath);
+ if (isRoot(filePath)) {
+ return jarIndex(url);
+ }
+ return loadString(url);
+ }
+
+ protected String jarIndex(URL url) throws IOException {
+ StringBuilder buffer = new StringBuilder();
+ JarURLConnection uc = (JarURLConnection) url.openConnection();
+ return jarIndex(uc.getJarFile());
+ }
+
+ protected String jarIndex(File file) throws IOException {
+ JarFile jarFile = new JarFile(file);
+ return jarIndex(jarFile);
+ }
+
+ protected String jarIndex(JarFile jarFile) {
+ StringBuilder buffer = new StringBuilder();
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ addJarEntryToIndex(entry, buffer);
+ }
+ return buffer.toString();
+ }
+
+ protected void addJarEntryToIndex(JarEntry entry, StringBuilder buffer) {
+ // no need to show empty directories
+ if (!entry.isDirectory()) {
+ buffer.append(entry.getName());
+ buffer.append("\n");
+ }
+ }
+
+
+
+ /**
+ * Returns true if the file path is "/" or empty
+ */
+ protected boolean isRoot(String filePath) {
+ return filePath == null || filePath.length() == 0 || filePath.equals("/");
+ }
+
+ public static String ensureStartsWithSlash(String path) {
+ if (path != null && !path.startsWith("/")) {
+ return "/" + path;
+ } else {
+ return path;
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LogQuerySupportMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LogQuerySupportMBean.java"
new file mode 100755
index 0000000..571dbcf
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LogQuerySupportMBean.java"
@@ -0,0 +1,83 @@
+package io.hawt.log.support;
+
+import java.io.IOException;
+
+import io.hawt.log.LogFilter;
+import io.hawt.log.LogResults;
+
+/**
+ * An MBean for querying log events which has a serialized API and a simple JSON API to avoid serialization issues
+ */
+public interface LogQuerySupportMBean {
+
+ /**
+ * Returns all the available recent log events as a {@link io.hawt.log.LogResults} object which is then serialized
+ *
+ * @return the log events as a serialized object
+ */
+ public LogResults allLogResults() throws IOException;
+
+ /**
+ * Returns all the available log events since the given timestamp (millis)
+ *
+ * @return the log events as a serialized object
+ */
+ public LogResults logResultsSince(long time) throws IOException;
+
+ /**
+ * Returns the recent log events as a {@link LogResults} object which is then serialized
+ *
+ * @param count maximum number to return o <0 for all of them
+ * @return the log events as a serialized object
+ */
+ public LogResults getLogResults(int count) throws IOException;
+
+ /**
+ * Queries the log results using the given filter
+ *
+ * @param filter the filter to apply to the logs
+ * @return the log events as a serialized object
+ */
+ public LogResults queryLogResults(LogFilter filter);
+
+
+ /**
+ * Returns the source file for the given maven coordinates so that we can link log messages
+ * to source code
+ *
+ * @param mavenCoordinates is a string of the form "groupId:artifactId:version".
+ * For some uber bundles this can be a space separated list.
+ */
+ public String getSource(String mavenCoordinates, String className, String filePath) throws IOException;
+
+ /**
+ * Returns the javadoc file for the given maven coordinates and filePath
+ *
+ * @param mavenCoordinates is a string of the form "groupId:artifactId:version".
+ * For some uber bundles this can be a space separated list.
+ */
+ public String getJavaDoc(String mavenCoordinates, String filePath) throws IOException;
+
+
+ // JSON API
+
+ /**
+ * Returns the recent log events as JSON
+ *
+ * @param count maximum number to return o <0 for all of them
+ * @return the log events as a blob of JSON using {@link io.hawt.log.LogEvent}
+ */
+ public String getLogEvents(int count) throws IOException;
+
+ /**
+ * Filters the list of log events using the JSON encoding of {@link io.hawt.log.LogFilter}
+ *
+ * @return the log events as a blob of JSON using {@link io.hawt.log.LogEvent}
+ */
+ public String filterLogEvents(String jsonFiler) throws IOException;
+
+ /**
+ * Allows a JSON filter to be specified then returns the log results as a serialised object
+ */
+ public LogResults jsonQueryLogResults(String jsonFilter) throws IOException;
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LruList.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LruList.java"
new file mode 100755
index 0000000..aec84a8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/LruList.java"
@@ -0,0 +1,87 @@
+package io.hawt.log.support;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+
+/**
+ * A simple LRU list that stores a fixed size
+ */
+public class LruList {
+ private final Class klass;
+ private final int size;
+ private T[] elements;
+ private transient int start = 0;
+ private transient int end = 0;
+ private transient boolean full = false;
+ private final int maxElements;
+
+ public LruList(Class klass, int size) {
+ this.klass = klass;
+ this.size = size;
+ if (size <= 0) {
+ throw new IllegalArgumentException("The size must be greater than 0");
+ }
+ elements = createArray(size);
+ maxElements = elements.length;
+ }
+
+ public synchronized int size() {
+ int size = 0;
+ if (end < start) {
+ size = maxElements - start + end;
+ } else if (end == start) {
+ size = (full ? maxElements : 0);
+ } else {
+ size = end - start;
+ }
+ return size;
+ }
+
+ public synchronized void clear() {
+ start = 0;
+ end = 0;
+ elements = createArray(size);
+ }
+
+ public synchronized void add(T element) {
+ if (null == element) {
+ throw new NullPointerException("Attempted to add null object to buffer");
+ }
+ if (size() == maxElements) {
+ Object e = elements[start];
+ if (null != e) {
+ elements[start++] = null;
+ if (start >= maxElements) {
+ start = 0;
+ }
+ full = false;
+ }
+ }
+ elements[end++] = element;
+ if (end >= maxElements) {
+ end = 0;
+ }
+ if (end == start) {
+ full = true;
+ }
+ }
+
+ public synchronized Iterable getElements() {
+ return getElements(size());
+ }
+
+ public synchronized Iterable getElements(int nb) {
+ int s = size();
+ nb = Math.min(Math.max(0, nb), s);
+ T[] e = createArray(nb);
+ for (int i = 0; i < nb; i++) {
+ e[i] = elements[(i + s - nb + start) % maxElements];
+ }
+ return Arrays.asList(e);
+ }
+
+ private T[] createArray(int size) {
+ return (T[]) Array.newInstance(klass, size);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/MavenCoordinates.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/MavenCoordinates.java"
new file mode 100755
index 0000000..a4056f9
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/MavenCoordinates.java"
@@ -0,0 +1,56 @@
+package io.hawt.log.support;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * A helper class for returning the coordinates from a Properties file
+ */
+public class MavenCoordinates {
+
+ public static String mavenCoordinateFromPomProperties(InputStream is) throws IOException {
+ StringBuilder builder = new StringBuilder();
+ appendMavenCoordinateFromPomProperties(is, builder);
+ return builder.toString();
+ }
+
+ public static void appendMavenCoordinateFromPomProperties(InputStream is, StringBuilder buffer) throws IOException {
+ Properties props = new Properties();
+ try {
+ props.load(is);
+ String groupId = props.getProperty("groupId");
+ String artifactId = props.getProperty("artifactId");
+ String version = props.getProperty("version");
+ if (groupId != null && artifactId != null & version != null) {
+ if (buffer.length() > 0) {
+ buffer.append(" ");
+ }
+ buffer.append(groupId).append(":").append(artifactId).append(":").append(version);
+ }
+ } finally {
+ is.close();
+ }
+ }
+
+ public static String mavenCoordinatesFromJarFile(File file) throws IOException {
+ StringBuilder buffer = new StringBuilder();
+ JarFile jarFile = new JarFile(file);
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry jarEntry = entries.nextElement();
+ String name = jarEntry.getName();
+ if (name.endsWith("pom.properties")) {
+ InputStream is = jarFile.getInputStream(jarEntry);
+ if (is != null) {
+ appendMavenCoordinateFromPomProperties(is, buffer);
+ }
+ }
+ }
+ return buffer.toString();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/Objects.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/Objects.java"
new file mode 100755
index 0000000..066cc85
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/Objects.java"
@@ -0,0 +1,56 @@
+package io.hawt.log.support;
+
+public final class Objects {
+
+ public static boolean isBlank(String text) {
+ return text == null || text.trim().length() == 0;
+ }
+
+ /**
+ * A helper method for comparing objects for equality while handling nulls
+ */
+ public static boolean equal(Object a, Object b) {
+ if (a == b) {
+ return true;
+ }
+ return a != null && b != null && a.equals(b);
+ }
+
+ /**
+ * A helper method for performing an ordered comparison on the objects
+ * handling nulls and objects which do not handle sorting gracefully
+ *
+ * @param a the first object
+ * @param b the second object
+ */
+ @SuppressWarnings("unchecked")
+ public static int compare(Object a, Object b) {
+ if (a == b) {
+ return 0;
+ }
+ if (a == null) {
+ return -1;
+ }
+ if (b == null) {
+ return 1;
+ }
+ if (a instanceof Comparable) {
+ Comparable comparable = (Comparable)a;
+ return comparable.compareTo(b);
+ }
+ int answer = a.getClass().getName().compareTo(b.getClass().getName());
+ if (answer == 0) {
+ answer = a.hashCode() - b.hashCode();
+ }
+ return answer;
+ }
+
+ public static boolean contains(String matchesText, String... values) {
+ for (String v : values) {
+ if (v != null && v.contains(matchesText)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/Predicate.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/Predicate.java"
new file mode 100755
index 0000000..0a505f9
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/main/java/io/hawt/log/support/Predicate.java"
@@ -0,0 +1,10 @@
+package io.hawt.log.support;
+
+/**
+ * Applies a predicate to a type; can be replaced by the Predicate from Guava later maybe?
+ */
+public interface Predicate {
+
+ boolean matches(T t);
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/test/java/io/hawt/log/log4j/Log4jLogQueryTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/test/java/io/hawt/log/log4j/Log4jLogQueryTest.java"
new file mode 100755
index 0000000..8e85e45
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/test/java/io/hawt/log/log4j/Log4jLogQueryTest.java"
@@ -0,0 +1,27 @@
+package io.hawt.log.log4j;
+
+import junit.framework.TestCase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Log4jLogQueryTest extends TestCase {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(Log4jLogQueryTest.class);
+ private Log4jLogQuery logQuery;
+
+ public void testLog4j() throws Exception {
+ logQuery = new Log4jLogQuery();
+ logQuery.start();
+
+ int size = logQuery.getEvents().size();
+
+ LOG.info("Hello hawtio");
+
+ int size2 = logQuery.getEvents().size();
+
+ assertTrue("There should be more logging events", size2 > size);
+
+ logQuery.stop();
+
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..5a1a4a7
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-log/src/test/resources/log4j.properties"
@@ -0,0 +1,16 @@
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, out
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/test.log
+log4j.appender.out.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/pom.xml"
new file mode 100755
index 0000000..5f552ef
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/pom.xml"
@@ -0,0 +1,117 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-system
+ ${project.artifactId}
+ hawtio :: hawtio-system
+
+
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${servlet-api-version}
+ provided
+
+
+
+ io.hawt
+ hawtio-core
+ ${project.version}
+
+
+
+ org.jolokia
+ jolokia-core
+ ${jolokia-version}
+
+
+
+ org.apache.karaf.jaas
+ org.apache.karaf.jaas.boot
+ ${karaf-version}
+ provided
+ true
+
+
+
+ org.osgi
+ org.osgi.core
+ ${osgi-version}
+ provided
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ ${httpclient-version}
+
+
+
+ commons-httpclient
+ commons-httpclient
+ ${commons-httpclient-version}
+
+
+
+ commons-io
+ commons-io
+ ${commons-io-version}
+
+
+
+ commons-codec
+ commons-codec
+ ${commons-codec-version}
+
+
+
+ com.google.guava
+ guava
+ ${guava-version}
+
+
+
+
+ org.json
+ json
+ ${org-json-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+ org.mockito
+ mockito-core
+ 2.20.0
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ test
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/HawtioContextListener.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/HawtioContextListener.java"
new file mode 100755
index 0000000..586a179
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/HawtioContextListener.java"
@@ -0,0 +1,82 @@
+package io.hawt;
+
+import java.util.Objects;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import io.hawt.jmx.About;
+import io.hawt.jmx.JMXSecurity;
+import io.hawt.jmx.JmxTreeWatcher;
+import io.hawt.jmx.PluginRegistry;
+import io.hawt.jmx.QuartzFacade;
+import io.hawt.jmx.RBACRegistry;
+import io.hawt.system.ConfigManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@link javax.servlet.ServletContextListener} which initialises key hawtio services in the webapp
+ */
+public class HawtioContextListener implements ServletContextListener {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HawtioContextListener.class);
+
+ private final About about;
+ private final QuartzFacade quartz;
+ private final JmxTreeWatcher treeWatcher;
+ private final PluginRegistry registry;
+ private final ConfigManager configManager;
+ private final JMXSecurity jmxSecurity;
+ private final RBACRegistry rbacRegistry;
+
+ public HawtioContextListener() {
+ this(new ConfigManager());
+ }
+
+ public HawtioContextListener(final ConfigManager configManager) {
+ this.configManager = Objects.requireNonNull(configManager);
+
+ this.about = new About();
+ this.quartz = new QuartzFacade();
+ this.treeWatcher = new JmxTreeWatcher();
+ this.registry = new PluginRegistry();
+ this.jmxSecurity = new JMXSecurity();
+ this.rbacRegistry = new RBACRegistry();
+ }
+
+ public void contextInitialized(ServletContextEvent servletContextEvent) {
+ LOGGER.info("Initialising hawtio services");
+ try {
+ about.init();
+ quartz.init();
+ configManager.init(servletContextEvent.getServletContext());
+ treeWatcher.init();
+ registry.init();
+ jmxSecurity.init();
+ rbacRegistry.init();
+ } catch (Exception e) {
+ throw createServletException(e);
+ }
+ servletContextEvent.getServletContext().setAttribute(ConfigManager.CONFIG_MANAGER, configManager);
+ }
+
+ public void contextDestroyed(ServletContextEvent servletContextEvent) {
+ LOGGER.info("Destroying hawtio services");
+ try {
+ rbacRegistry.destroy();
+ about.destroy();
+ quartz.destroy();
+ treeWatcher.destroy();
+ registry.destroy();
+ configManager.destroy();
+ jmxSecurity.destroy();
+ } catch (Exception e) {
+ throw createServletException(e);
+ }
+ }
+
+ protected RuntimeException createServletException(Exception e) {
+ return new RuntimeException(e);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/About.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/About.java"
new file mode 100755
index 0000000..9d3a9aa
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/About.java"
@@ -0,0 +1,135 @@
+package io.hawt.jmx;
+
+import java.io.InputStream;
+import java.lang.management.ManagementFactory;
+import java.util.Properties;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import io.hawt.util.Objects;
+
+public class About implements AboutMBean {
+
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+ private String hawtioVersion;
+
+ public void init() throws Exception {
+ if (objectName == null) {
+ objectName = getObjectName();
+ }
+
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+
+ if (mBeanServer != null) {
+ try {
+ mBeanServer.registerMBean(this, objectName);
+ } catch (InstanceAlreadyExistsException iaee) {
+ // Try to remove and re-register
+ mBeanServer.unregisterMBean(objectName);
+ mBeanServer.registerMBean(this, objectName);
+ }
+
+ // try to compute hawtio version once on startup
+ try {
+ hawtioVersion = doGetHawtioVersion();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ public void destroy() throws Exception {
+ if (mBeanServer != null) {
+ if (objectName != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+ }
+
+ protected ObjectName getObjectName() throws Exception {
+ return new ObjectName("hawtio:type=About");
+ }
+
+ @Override
+ public String getHawtioVersion() {
+ if (hawtioVersion != null) {
+ return hawtioVersion;
+ }
+ return doGetHawtioVersion();
+ }
+
+ private synchronized String doGetHawtioVersion() {
+ // loading the version can be tricky depending on how hawtio has been started, so we try different strategies
+
+ String version = Objects.getVersion(getClass(), "io.hawt", "hawtio-web");
+ if (version == null) {
+ version = Objects.getVersion(getClass(), "io.hawt", "hawtio-app");
+ }
+ if (version == null) {
+ version = Objects.getVersion(getClass(), "io.hawt", "hawtio-default");
+ }
+ if (version != null) {
+ return version;
+ }
+
+ InputStream is = null;
+ try {
+ Properties p = new Properties();
+
+ // try to load from maven properties first as they have the version
+ is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/META-INF/maven/io.hawt/hawtio-web/pom.properties");
+ if (is == null) {
+ is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/META-INF/maven/io.hawt/hawtio-default/pom.properties");
+ }
+ if (is == null) {
+ is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/META-INF/maven/io.hawt/hawtio-app/pom.properties");
+ }
+ if (is == null) {
+ is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/META-INF/maven/io.hawt/hawtio-embedded/pom.properties");
+ }
+ // then try the general manifest file
+ is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/META-INF/MANIFEST.MF");
+ if (is != null) {
+ p.load(is);
+ version = p.getProperty("Bundle-Version", null);
+ if (version == null) {
+ version = p.getProperty("version", "");
+ }
+ }
+ } catch (Exception e) {
+ // ignore
+ e.printStackTrace();
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ // fallback to using Java API
+ if (version == null) {
+ Package aPackage = Thread.currentThread().getContextClassLoader().getClass().getPackage();
+ if (aPackage != null) {
+ version = aPackage.getImplementationVersion();
+ if (version == null) {
+ version = aPackage.getSpecificationVersion();
+ }
+ }
+ }
+
+ if (version == null) {
+ // we could not compute the version so use a blank
+ version = "";
+ }
+
+ return version;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/AboutMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/AboutMBean.java"
new file mode 100755
index 0000000..99a2d03
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/AboutMBean.java"
@@ -0,0 +1,7 @@
+package io.hawt.jmx;
+
+public interface AboutMBean {
+
+ String getHawtioVersion();
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/FileDTO.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/FileDTO.java"
new file mode 100755
index 0000000..eee793d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/FileDTO.java"
@@ -0,0 +1,43 @@
+package io.hawt.jmx;
+
+import java.io.File;
+
+/**
+ * File DTO
+ */
+public class FileDTO {
+
+ private String absolutePath;
+ private String fileName;
+ private long length;
+
+ public FileDTO(File file) {
+ this.absolutePath = file.getAbsolutePath();
+ this.fileName = file.getName();
+ this.length = file.length();
+ }
+
+ public String getAbsolutePath() {
+ return absolutePath;
+ }
+
+ public void setAbsolutePath(String absolutePath) {
+ this.absolutePath = absolutePath;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public void setLength(long length) {
+ this.length = length;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JMXSecurity.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JMXSecurity.java"
new file mode 100755
index 0000000..e91b8f5
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JMXSecurity.java"
@@ -0,0 +1,63 @@
+package io.hawt.jmx;
+
+import java.util.List;
+import java.util.Map;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+
+import io.hawt.util.MBeanSupport;
+
+/**
+ * Dummy version that implements JMXSecurityMBean that lets the current user
+ * invoke anything
+ */
+public class JMXSecurity extends MBeanSupport implements JMXSecurityMBean {
+
+ @Override
+ public boolean canInvoke(String objectName) throws Exception {
+ return true;
+ }
+
+ @Override
+ public boolean canInvoke(String objectName, String methodName) throws Exception {
+ return true;
+ }
+
+ @Override
+ public boolean canInvoke(String objectName, String methodName, String[] argumentTypes) throws Exception {
+ return true;
+ }
+
+ @Override
+ public TabularData canInvoke(Map> bulkQuery) throws Exception {
+ TabularData table = new TabularDataSupport(CAN_INVOKE_TABULAR_TYPE);
+
+ for (Map.Entry> entry : bulkQuery.entrySet()) {
+ String objectName = entry.getKey();
+ List methods = entry.getValue();
+ if (methods.size() == 0) {
+ boolean res = canInvoke(objectName);
+ CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE,
+ CAN_INVOKE_RESULT_COLUMNS,
+ new Object[]{objectName, "", true});
+ table.put(data);
+ } else {
+ for (String method : methods) {
+ CompositeData data = new CompositeDataSupport(CAN_INVOKE_RESULT_ROW_TYPE,
+ CAN_INVOKE_RESULT_COLUMNS,
+ new Object[]{objectName, method, true});
+ table.put(data);
+ }
+ }
+ }
+
+ return table;
+ }
+
+ @Override
+ protected String getDefaultObjectName() {
+ return "hawtio:type=security,area=jmx,rank=0,name=HawtioDummyJMXSecurity";
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JMXSecurityMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JMXSecurityMBean.java"
new file mode 100755
index 0000000..2976b1a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JMXSecurityMBean.java"
@@ -0,0 +1,134 @@
+package io.hawt.jmx;
+
+import java.util.List;
+import java.util.Map;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+
+
+/**
+ * Snagged from Apache Karaf 3.x
+ *
+ * Security MBean. This MBean can be used to find out whether the currently logged in user can access
+ * certain MBeans or invoke operations on these MBeans. It can be used when building client-facing
+ * consoles to ensure that only operations appropriate for the current user are presented.
+ * This MBean does not actually invoke any operations on the given objects, it only checks permissions.
+ */
+public interface JMXSecurityMBean {
+ /**
+ * The Tabular Type returned by the {@link #canInvoke(Map)} operation. The rows consist of
+ * {@link #CAN_INVOKE_RESULT_ROW_TYPE} entries.
+ * It has a composite key with consists of the "ObjectName" and "Method" columns.
+ */
+ static final TabularType CAN_INVOKE_TABULAR_TYPE = SecurityMBeanOpenTypeInitializer.TABULAR_TYPE;
+
+ /**
+ * A row as returned by the {@link #CAN_INVOKE_TABULAR_TYPE}. The columns of the row are defined
+ * by {@link #CAN_INVOKE_RESULT_COLUMNS}.
+ */
+ static final CompositeType CAN_INVOKE_RESULT_ROW_TYPE = SecurityMBeanOpenTypeInitializer.ROW_TYPE;
+
+ /**
+ * The columns contained in a {@link #CAN_INVOKE_RESULT_ROW_TYPE}. The data types for these columns are
+ * as follows:
+ *
+ * "ObjectName" : {@link SimpleType#STRING}
+ * "Method" : {@link SimpleType#STRING}
+ * "CanInvoke" : {@link SimpleType#BOOLEAN}
+ *
+ */
+ static final String[] CAN_INVOKE_RESULT_COLUMNS = SecurityMBeanOpenTypeInitializer.COLUMNS;
+
+ /**
+ * Checks whether the current user can invoke any methods on a JMX MBean.
+ *
+ * @param objectName The Object Name of the JMX MBean.
+ * @return {@code true} if there is at least one method on the MBean that the
+ * user can invoke.
+ */
+ boolean canInvoke(String objectName) throws Exception;
+
+ /**
+ * Checks whether the current user can invoke any overload of the given method.
+ *
+ * @param objectName The Object Name of the JMX MBean.
+ * @param methodName The name of the method to check.
+ * @return {@code true} if there is an overload of the specified method that the
+ * user can invoke.
+ */
+ boolean canInvoke(String objectName, String methodName) throws Exception;
+
+ /**
+ * Checks whether the current user can invoke the given method.
+ *
+ * @param objectName The Object Name of the JMX MBean.
+ * @param methodName The name of the method to check.
+ * @param argumentTypes The argument types of to method.
+ * @return {@code true} if the user is allowed to invoke the method, or any of the methods with
+ * the given name if {@code null} is used for the arguments. There may still
+ * be certain values that the user does not have permission to pass to the method.
+ */
+ boolean canInvoke(String objectName, String methodName, String[] argumentTypes) throws Exception;
+
+ /**
+ * Bulk operation to check whether the current user can access the requested MBeans or invoke the
+ * requested methods.
+ *
+ * @param bulkQuery A map of Object Name to requested operations. Operations can be specified
+ * with or without arguments types. An operation without arguments matches any overloaded method
+ * with this name. If an empty list is provided for the operation names, a check is done whether the
+ * current user can invoke any operation on the MBean.
+ * Example:
+ * {@code
+ * Map> query = new HashMap<>();
+ * String objectName = "org.acme:type=SomeMBean";
+ * query.put(objectName, Arrays.asList(
+ * "testMethod(long,java.lang.String)", // check this testMethod
+ * "otherMethod")); // check any overload of otherMethod
+ * query.put("org.acme:type=SomeOtherMBean",
+ * Collections.emptyList()); // check any method of SomeOtherMBean
+ * TabularData result = mb.canInvoke(query);
+ * }
+ * @return A Tabular Data object with the result. This object conforms the structure as defined
+ * in {@link #CAN_INVOKE_TABULAR_TYPE}.
+ */
+ TabularData canInvoke(Map> bulkQuery) throws Exception;
+
+ // A member class is used to initialize final fields, as this needs to do some exception handling...
+ static class SecurityMBeanOpenTypeInitializer {
+ private static final String[] COLUMNS = new String[]{"ObjectName", "Method", "CanInvoke"};
+ private static final CompositeType ROW_TYPE;
+
+ static {
+ try {
+ ROW_TYPE = new CompositeType("CanInvokeRowType",
+ "The rows of a CanInvokeTabularType table.",
+ COLUMNS,
+ new String[]{
+ "The ObjectName of the MBean checked",
+ "The Method to checked. This can either be a bare method name which means 'any method with this name' " +
+ "or a specific overload such as foo(java.lang.String). If an empty String is returned this means 'any' method.",
+ "true if the method or mbean can potentially be invoked by the current user."},
+ new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.BOOLEAN}
+ );
+ } catch (OpenDataException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static final TabularType TABULAR_TYPE;
+
+ static {
+ try {
+ TABULAR_TYPE = new TabularType("CanInvokeTabularType", "Result of canInvoke() bulk operation", ROW_TYPE,
+ new String[]{"ObjectName", "Method"});
+ } catch (OpenDataException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JmxTreeWatcher.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JmxTreeWatcher.java"
new file mode 100755
index 0000000..a413e17
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JmxTreeWatcher.java"
@@ -0,0 +1,114 @@
+package io.hawt.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerDelegate;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import io.hawt.util.Objects;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A simple mbean to watch the JMX tree so its easy for clients to know when they should refresh
+ * their JMX trees (which typically isn't a cheap operation).
+ */
+public class JmxTreeWatcher implements JmxTreeWatcherMBean {
+ private static final transient Logger LOG = LoggerFactory.getLogger(JmxTreeWatcher.class);
+ private static AtomicBoolean logged = new AtomicBoolean();
+
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+ private AtomicLong counter = new AtomicLong(0);
+ private NotificationListener listener;
+ private NotificationFilter filter;
+ private String version;
+
+ public void init() throws Exception {
+ if (objectName == null) {
+ objectName = getObjectName();
+ }
+
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+
+ if (mBeanServer != null) {
+ try {
+ mBeanServer.registerMBean(this, objectName);
+ } catch (InstanceAlreadyExistsException iaee) {
+ // Try to remove and re-register
+ mBeanServer.unregisterMBean(objectName);
+ mBeanServer.registerMBean(this, objectName);
+ }
+
+ Object handback = null;
+
+ listener = getNotificationListener();
+ filter = getNotificationFilter();
+
+ mBeanServer.addNotificationListener(MBeanServerDelegate.DELEGATE_NAME, listener, filter, handback);
+ }
+ if (logged.compareAndSet(false, true)) {
+ LOG.info("Welcome to Hawtio {}", getVersion());
+ }
+ }
+
+ public void destroy() throws Exception {
+ if (mBeanServer != null) {
+ if (listener != null) {
+ mBeanServer.removeNotificationListener(MBeanServerDelegate.DELEGATE_NAME, listener);
+ }
+ if (objectName != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+ }
+
+ public String getVersion() {
+ if (version == null) {
+ try {
+ version = Objects.getVersion(JmxTreeWatcher.class, "io.hawt", "hawtio-web");
+ } catch (Exception e) {
+ // ignore
+ }
+ if (version == null) {
+ version = "";
+ }
+ }
+ return version;
+ }
+
+ protected ObjectName getObjectName() throws Exception {
+ return new ObjectName("hawtio:type=TreeWatcher");
+ }
+
+ protected NotificationListener getNotificationListener() {
+ return (notification, handback) -> {
+ // TODO should we filter only types "JMX.mbean.registered" and "JMX.mbean.unregistered"?
+ counter.incrementAndGet();
+ };
+ }
+
+ protected NotificationFilter getNotificationFilter() {
+ return new NotificationFilter() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean isNotificationEnabled(Notification notification) {
+ return true;
+ }
+ };
+ }
+
+ @Override
+ public long getCounter() {
+ return counter.get();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JmxTreeWatcherMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JmxTreeWatcherMBean.java"
new file mode 100755
index 0000000..6bd995c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/JmxTreeWatcherMBean.java"
@@ -0,0 +1,7 @@
+package io.hawt.jmx;
+
+public interface JmxTreeWatcherMBean {
+
+ long getCounter();
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/PluginRegistry.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/PluginRegistry.java"
new file mode 100755
index 0000000..5f1fbf8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/PluginRegistry.java"
@@ -0,0 +1,75 @@
+package io.hawt.jmx;
+
+import java.util.concurrent.atomic.AtomicLong;
+import javax.management.MBeanServerNotification;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Hawtio plugin registry
+ */
+public class PluginRegistry extends JmxTreeWatcher implements PluginRegistryMBean {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(PluginRegistry.class);
+
+ private AtomicLong updateCounter = new AtomicLong(0);
+ private ObjectName comparator = null;
+
+ public PluginRegistry() {
+ }
+
+ @Override
+ public void init() {
+ try {
+ comparator = new ObjectName("hawtio:type=plugin,name=*");
+ super.init();
+ } catch (MalformedObjectNameException mone) {
+ LOG.error("Failed to initialize comparator object name", mone);
+ } catch (Exception e) {
+ LOG.error("Failed to initialize plugin registry: ", e);
+ }
+ }
+
+ @Override
+ protected ObjectName getObjectName() throws Exception {
+ return new ObjectName("hawtio:type=Registry");
+ }
+
+ protected NotificationListener getNotificationListener() {
+ return new NotificationListener() {
+ @Override
+ public void handleNotification(Notification notification, Object handback) {
+ LOG.debug("Got notification: " + notification + " for object " + handback);
+ updateCounter.incrementAndGet();
+ }
+ };
+ }
+
+ protected NotificationFilter getNotificationFilter() {
+ return new NotificationFilter() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean isNotificationEnabled(Notification notification) {
+ if (notification instanceof MBeanServerNotification) {
+ MBeanServerNotification n = (MBeanServerNotification) notification;
+ return comparator.apply(n.getMBeanName());
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public long getUpdateCounter() {
+ return updateCounter.get();
+ }
+
+}
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/PluginRegistryMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/PluginRegistryMBean.java"
new file mode 100755
index 0000000..6f0319f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/PluginRegistryMBean.java"
@@ -0,0 +1,8 @@
+package io.hawt.jmx;
+
+public interface PluginRegistryMBean {
+
+ public long getUpdateCounter();
+
+}
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/QuartzFacade.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/QuartzFacade.java"
new file mode 100755
index 0000000..62b4587
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/QuartzFacade.java"
@@ -0,0 +1,172 @@
+package io.hawt.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+public class QuartzFacade implements QuartzFacadeMBean {
+
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+
+ public void init() throws Exception {
+ if (objectName == null) {
+ objectName = getObjectName();
+ }
+
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+
+ if (mBeanServer != null) {
+ try {
+ mBeanServer.registerMBean(this, objectName);
+ } catch (InstanceAlreadyExistsException iaee) {
+ // Try to remove and re-register
+ mBeanServer.unregisterMBean(objectName);
+ mBeanServer.registerMBean(this, objectName);
+ }
+ }
+ }
+
+ public void destroy() throws Exception {
+ if (mBeanServer != null) {
+ if (objectName != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+ }
+
+ protected ObjectName getObjectName() throws Exception {
+ return new ObjectName("hawtio:type=QuartzFacade");
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void updateSimpleTrigger(String schedulerObjectName, String triggerName, String groupName, int misfireInstruction,
+ int repeatCount, long repeatInterval) throws Exception {
+ if (schedulerObjectName == null) {
+ throw new IllegalArgumentException("Cannot find quartz scheduler with ObjectName: " + schedulerObjectName);
+ }
+
+ ObjectName on = ObjectName.getInstance(schedulerObjectName);
+ if (!mBeanServer.isRegistered(on)) {
+ throw new IllegalArgumentException("Cannot find quartz scheduler with ObjectName: " + schedulerObjectName);
+ }
+
+ // get existing trigger map
+ CompositeData data = (CompositeData) mBeanServer.invoke(on, "getTrigger", new Object[]{triggerName, groupName}, new String[]{"java.lang.String", "java.lang.String"});
+ if (data == null) {
+ throw new IllegalArgumentException("Cannot find trigger details for group: " + groupName + " name: " + triggerName);
+ }
+ // trigger references job - let's get its data
+ String jobName = (String) data.get("jobName");
+ String jobGroupName = (String) data.get("jobGroup");
+ CompositeData jobData = (CompositeData) mBeanServer.invoke(on, "getJobDetail", new Object[]{jobName, jobGroupName}, new String[]{"java.lang.String", "java.lang.String"});
+ if (jobData == null) {
+ throw new IllegalArgumentException("Cannot find job details for group: " + jobGroupName + " name: " + jobName);
+ }
+
+ Map jobParams = new HashMap();
+ Map jobDataMap = new HashMap();
+ initJobParams(jobParams, jobDataMap, jobName, jobGroupName, jobData);
+
+ // also ensure the job data map is up to date with the simple trigger changes
+ Map triggerParams = new HashMap();
+ jobDataMap.put("CamelQuartzTriggerType", "simple");
+ triggerParams.put("repeatCount", repeatCount);
+ jobDataMap.put("CamelQuartzTriggerSimpleRepeatCounter", repeatCount);
+ triggerParams.put("repeatInterval", repeatInterval);
+ jobDataMap.put("CamelQuartzTriggerSimpleRepeatInterval", repeatInterval);
+ triggerParams.put("name", triggerName);
+ triggerParams.put("group", groupName);
+ triggerParams.put("jobName", jobName);
+ triggerParams.put("jobGroup", jobGroupName);
+ triggerParams.put("misfireInstruction", misfireInstruction);
+
+ // update trigger
+ mBeanServer.invoke(on, "scheduleBasicJob", new Object[]{jobParams, triggerParams}, new String[]{"java.util.Map", "java.util.Map"});
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void updateCronTrigger(String schedulerObjectName, String triggerName, String groupName, int misfireInstruction,
+ String cronExpression, String timeZone) throws Exception {
+ if (schedulerObjectName == null) {
+ throw new IllegalArgumentException("Cannot find quartz scheduler with ObjectName: " + schedulerObjectName);
+ }
+
+ ObjectName on = ObjectName.getInstance(schedulerObjectName);
+ if (!mBeanServer.isRegistered(on)) {
+ throw new IllegalArgumentException("Cannot find quartz scheduler with ObjectName: " + schedulerObjectName);
+ }
+
+ // get existing trigger map
+ CompositeData data = (CompositeData) mBeanServer.invoke(on, "getTrigger", new Object[]{triggerName, groupName}, new String[]{"java.lang.String", "java.lang.String"});
+ if (data == null) {
+ throw new IllegalArgumentException("Cannot find trigger details for group: " + groupName + " name: " + triggerName);
+ }
+ // trigger references job - let's get its data
+ String jobName = (String) data.get("jobName");
+ String jobGroupName = (String) data.get("jobGroup");
+ CompositeData jobData = (CompositeData) mBeanServer.invoke(on, "getJobDetail", new Object[]{jobName, jobGroupName}, new String[]{"java.lang.String", "java.lang.String"});
+ if (jobData == null) {
+ throw new IllegalArgumentException("Cannot find job details for group: " + jobGroupName + " name: " + jobName);
+ }
+
+ Map jobParams = new HashMap();
+ Map jobDataMap = new HashMap();
+ initJobParams(jobParams, jobDataMap, jobName, jobGroupName, jobData);
+
+ Map triggerParams = new HashMap();
+ jobDataMap.put("CamelQuartzTriggerType", "cron");
+ // also ensure the job data map is up to date with the cron trigger changes
+ triggerParams.put("cronExpression", cronExpression);
+ jobDataMap.put("CamelQuartzTriggerCronExpression", cronExpression);
+ if (timeZone != null) {
+ triggerParams.put("timeZone", timeZone);
+ jobDataMap.put("CamelQuartzTriggerCronTimeZone", timeZone);
+ }
+ triggerParams.put("name", triggerName);
+ triggerParams.put("group", groupName);
+ triggerParams.put("jobName", jobName);
+ triggerParams.put("jobGroup", jobGroupName);
+ triggerParams.put("misfireInstruction", misfireInstruction);
+
+ // update trigger
+ mBeanServer.invoke(on, "scheduleBasicJob", new Object[]{jobParams, triggerParams}, new String[]{"java.util.Map", "java.util.Map"});
+ }
+
+ private void initJobParams(Map jobParams, Map jobDataMap, String triggerName, String groupName, CompositeData data) {
+ jobParams.put("name", triggerName);
+ jobParams.put("group", groupName);
+ if (data.get("description") != null) {
+ jobParams.put("description", data.get("description"));
+ }
+ jobParams.put("jobClass", data.get("jobClass"));
+ jobParams.put("durability", data.get("durability"));
+ jobParams.put("shouldRecover", data.get("shouldRecover"));
+ // JMX API with TabularData and CompositeData is cluttered to use
+ TabularData tJobDataMap = (TabularData) data.get("jobDataMap");
+ for (Object cKey : tJobDataMap.keySet()) {
+ Object key = ((List) cKey).get(0);
+ Object value = tJobDataMap.get(new Object[]{key});
+ if (value != null) {
+ CompositeData cd = (CompositeData) value;
+ Iterator it = cd.values().iterator();
+ Object tKey = it.next();
+ Object tValue = it.next();
+ jobDataMap.put(tKey, tValue);
+ }
+ }
+ jobParams.put("jobDataMap", jobDataMap);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/QuartzFacadeMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/QuartzFacadeMBean.java"
new file mode 100755
index 0000000..d1e8f49
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/QuartzFacadeMBean.java"
@@ -0,0 +1,25 @@
+package io.hawt.jmx;
+
+public interface QuartzFacadeMBean {
+
+ /**
+ * Updates an existing simple trigger by changing the repeat counter and interval values.
+ *
+ * @param misfireInstruction the misfire instruction
+ * @param repeatCount the repeat count (use 0 for forever)
+ * @param repeatInterval the repeat interval in millis
+ */
+ void updateSimpleTrigger(String schedulerObjectName, String triggerName, String groupName, int misfireInstruction,
+ int repeatCount, long repeatInterval) throws Exception;
+
+ /**
+ * Updates an existing cron trigger by changing the cron expression
+ *
+ * @param misfireInstruction the misfire instruction
+ * @param cronExpression the cron expressions
+ * @param timeZone optional time zone
+ */
+ void updateCronTrigger(String schedulerObjectName, String triggerName, String groupName, int misfireInstruction,
+ String cronExpression, String timeZone) throws Exception;
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/RBACRegistry.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/RBACRegistry.java"
new file mode 100755
index 0000000..6adcd7d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/RBACRegistry.java"
@@ -0,0 +1,318 @@
+/**
+ * Copyright 2005-2016 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Generally we do enhanced Jolokia list operation, but if OSGi env is found we decorate the returned
+ * objects with RBAC information.
+ */
+public class RBACRegistry implements RBACRegistryMBean {
+
+ public static Logger LOG = LoggerFactory.getLogger(RBACRegistry.class);
+
+ private ObjectName rbacDecorator = null;
+
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+
+ public void init() throws Exception {
+ if (objectName == null) {
+ objectName = new ObjectName("hawtio:type=security,name=RBACRegistry");
+ }
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ if (mBeanServer != null) {
+ rbacDecorator = new ObjectName("hawtio:type=security,area=jolokia,name=RBACDecorator");
+ try {
+ mBeanServer.registerMBean(this, objectName);
+ } catch (InstanceAlreadyExistsException iaee) {
+ // Try to remove and re-register
+ mBeanServer.unregisterMBean(objectName);
+ mBeanServer.registerMBean(this, objectName);
+ }
+ }
+ }
+
+ public void destroy() throws Exception {
+ if (objectName != null && mBeanServer != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+
+ @Override
+ public Map list() throws Exception {
+ Map result = new HashMap<>();
+
+ // domain -> [mbean, mbean, ...], where mbean is either inline jsonified MBeanInfo or a key to shared
+ // jsonified MBeanInfo
+ Map> domains = new HashMap<>();
+ // if MBean is found to be "special", we can cache JSONified MBeanInfo (an object with "op", "attr" and "desc"
+ // properties)
+ // key -> [mbeaninfo, mbeaninfo, ...]
+ Map> cache = new HashMap<>();
+
+ result.put("cache", cache);
+ result.put("domains", domains);
+
+ if (mBeanServer == null) {
+ return result;
+ }
+
+ Set visited = new HashSet<>();
+
+ // see: org.jolokia.backend.executor.AbstractMBeanServerExecutor.each()
+ for (ObjectName nameObject : mBeanServer.queryNames(null, null)) {
+ // Don't add if already visited previously
+ if (!visited.contains(nameObject)) {
+ Map jsonifiedMBeanInfo;
+
+ Map domain = domains.get(nameObject.getDomain());
+ if (domain == null) {
+ domain = new HashMap<>();
+ domains.put(nameObject.getDomain(), domain);
+ }
+
+ // Let's try to avoid invoking getMBeanInfo. simply domain+type attr is not enough, but we may
+ // detect special cases
+ String mbeanInfoKey = isSpecialMBean(nameObject);
+ if (mbeanInfoKey != null && cache.containsKey(mbeanInfoKey)) {
+ jsonifiedMBeanInfo = cache.get(mbeanInfoKey);
+ } else {
+ // we may have to assemble the info on the fly
+ try {
+ MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(nameObject);
+
+ // 2nd level of special cases - a bit slower (we had to getMBeanInfo(), but we may try
+ // cache by MBean's domain and class)
+ if (mbeanInfoKey == null) {
+ mbeanInfoKey = isSpecialClass(nameObject, mBeanInfo);
+ }
+ if (mbeanInfoKey != null && cache.containsKey(mbeanInfoKey)) {
+ jsonifiedMBeanInfo = cache.get(mbeanInfoKey);
+ } else {
+ // hard work here
+ jsonifiedMBeanInfo = jsonifyMBeanInfo(mBeanInfo);
+ }
+
+ if (mbeanInfoKey != null) {
+ cache.put(mbeanInfoKey, jsonifiedMBeanInfo);
+ }
+ } catch (InstanceNotFoundException e) {
+ // Log failure and continue so that we can still send a response back
+ LOG.debug("Failed to get MBean info for {}. Due to InstanceNotFoundException.", nameObject);
+ continue;
+ }
+ }
+
+ // jsonifiedMBeanInfo should not be null here and *may* be cached
+ if (mbeanInfoKey != null) {
+ // in hawtio we'll check `typeof info === 'string'` (angular.isString(info))
+ domain.put(nameObject.getKeyPropertyListString(), mbeanInfoKey);
+ } else {
+ // angular.isObject(info)
+ domain.put(nameObject.getKeyPropertyListString(), jsonifiedMBeanInfo);
+ }
+
+ visited.add(nameObject);
+ }
+ }
+
+ tryAddRBACInfo(result);
+
+ return result;
+ }
+
+ /**
+ * This method duplicates what Jolokia does in List Handler in order to convert {@link MBeanInfo} to JSON.
+ * @param mBeanInfo
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ private Map jsonifyMBeanInfo(MBeanInfo mBeanInfo) {
+ Map result = new LinkedHashMap<>();
+
+ // desc
+ result.put("desc", mBeanInfo.getDescription());
+
+ // attr
+ Map attrMap = new LinkedHashMap<>();
+ result.put("attr", attrMap);
+ for (MBeanAttributeInfo attrInfo : mBeanInfo.getAttributes()) {
+ if (attrInfo == null) {
+ continue;
+ }
+ Map attr = new HashMap<>();
+ attr.put("type", attrInfo.getType());
+ attr.put("desc", attrInfo.getDescription());
+ attr.put("rw", attrInfo.isWritable() && attrInfo.isReadable());
+ attrMap.put(attrInfo.getName(), attr);
+ }
+
+ // op
+ Map opMap = new LinkedHashMap<>();
+ result.put("op", opMap);
+ for (MBeanOperationInfo opInfo : mBeanInfo.getOperations()) {
+ Map map = new HashMap<>();
+ List> argList = new ArrayList<>(opInfo.getSignature().length);
+ for (MBeanParameterInfo paramInfo : opInfo.getSignature()) {
+ Map args = new HashMap<>();
+ args.put("desc", paramInfo.getDescription());
+ args.put("name", paramInfo.getName());
+ args.put("type", paramInfo.getType());
+ argList.add(args);
+ }
+ map.put("args", argList);
+ map.put("ret", opInfo.getReturnType());
+ map.put("desc", opInfo.getDescription());
+ Object ops = opMap.get(opInfo.getName());
+ if (ops != null) {
+ if (ops instanceof List) {
+ // If it is already a list, simply add it to the end
+ ((List) ops).add(map);
+ } else if (ops instanceof Map) {
+ // If it is a map, add a list with two elements
+ // (the old one and the new one)
+ List opList = new LinkedList<>();
+ opList.add(ops);
+ opList.add(map);
+ opMap.put(opInfo.getName(), opList);
+ }
+ } else {
+ // No value set yet, simply add the map as plain value
+ opMap.put(opInfo.getName(), map);
+ }
+ }
+
+ // not
+ Map notMap = new LinkedHashMap<>();
+ result.put("not", notMap);
+ for (MBeanNotificationInfo notInfo : mBeanInfo.getNotifications()) {
+ Map map = new HashMap<>();
+ map.put("name", notInfo.getName());
+ map.put("desc", notInfo.getDescription());
+ String[] types = notInfo.getNotifTypes();
+ List tList = new ArrayList<>(types.length);
+ Collections.addAll(tList, types);
+ map.put("types", tList);
+ notMap.put(notInfo.getName(), map);
+ }
+
+ // this is default - in case we won't find RBACDecorator (possible in hawtio-wildfly for example)
+ result.put("canInvoke", true);
+
+ return result;
+ }
+
+ /**
+ * If the {@link ObjectName} is detected as special (when we may have thousands of such MBeans), we
+ * return a key to lookup already processed {@link MBeanInfo}
+ * @param nameObject
+ * @return
+ */
+ private String isSpecialMBean(ObjectName nameObject) {
+ String domain = nameObject.getDomain();
+ if ("org.apache.activemq".equals(domain)) {
+ String destinationType = nameObject.getKeyProperty("destinationType");
+ // see: org.apache.activemq.command.ActiveMQDestination.getDestinationTypeAsString()
+ if ("Queue".equals(destinationType)) {
+ return "activemq:queue";
+ }
+ if ("TempQueue".equals(destinationType)) {
+ return "activemq:tempqueue";
+ }
+ if ("Topic".equals(destinationType)) {
+ return "activemq:topic";
+ }
+ if ("TempTopic".equals(destinationType)) {
+ return "activemq:temptopic";
+ }
+ } else if ("org.apache.camel".equals(domain)) {
+ String type = nameObject.getKeyProperty("type");
+ // TODO: verify: "type" attribute is not enough - we have to know real class of MBean
+ return null;
+ }
+
+ return null;
+ }
+
+ /**
+ * If some combination of {@link ObjectName} and MBean's class name is detected as special , we may
+ * cache the JSONified {@link MBeanInfo} as well
+ * @param nameObject
+ * @param mBeanInfo
+ * @return
+ */
+ private String isSpecialClass(ObjectName nameObject, MBeanInfo mBeanInfo) {
+ String domain = nameObject.getDomain();
+ if ("org.apache.camel".equals(domain) && mBeanInfo.getClassName() != null) {
+ // some real data in env with 12 Camel contexts deployed
+ // - components (total: 102)
+ // - consumers (total: 511)
+ // - context (total: 12)
+ // - endpoints (total: 818)
+ // - errorhandlers (total: 12)
+ // - eventnotifiers (total: 24)
+ // - processors (total: 3600)
+ // - producers (total: 1764)
+ // - routes (total: 511)
+ // - services (total: 548)
+ // - threadpools (total: 66)
+ // - tracer (total: 24)
+ return "camel::" + mBeanInfo.getClassName();
+ }
+
+ return null;
+ }
+
+ /**
+ * If we have access to hawtio:type=security,area=jolokia,name=RBACDecorator,
+ * we can add RBAC information
+ * @param result
+ */
+ @SuppressWarnings("unchecked")
+ private void tryAddRBACInfo(Map result) throws MBeanException, InstanceNotFoundException, ReflectionException {
+ if (mBeanServer != null && mBeanServer.isRegistered(rbacDecorator)) {
+ mBeanServer.invoke(rbacDecorator, "decorate", new Object[] { result }, new String[] { Map.class.getName() });
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/RBACRegistryMBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/RBACRegistryMBean.java"
new file mode 100755
index 0000000..9267817
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/jmx/RBACRegistryMBean.java"
@@ -0,0 +1,42 @@
+/**
+ * Copyright 2005-2016 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.jmx;
+
+import java.util.Map;
+
+/**
+ * MBean that optimizes access to Karaf's RBAC services.
+ * When doing client-side initialization, hawtio invokes two time-consuming operations:
+ * LIST of available MBeans (with metadata consisting in attrs, ops, description
+ * EXEC for org.apache.karaf.management.JMXSecurityMBean#canInvoke(java.util.Map)
+ *
+ * This becomes unacceptable when we have hundreds of similar MBeans (like ActiveMQ queues or Camel
+ * components/endpoints/processors/routes/consumers/...
+ * The role of this MBean is to combine LIST+EXEC/RBAC operations into one - and return
+ * map that is complete, but optimized (uses shared JSON elements that can be processed by hawtio client
+ * app itself).
+ */
+public interface RBACRegistryMBean {
+
+ /**
+ * Returns {@link Map} (that can be nicely handled by Jolokia) containing everything that is initially
+ * needed by hawtio client application. It's an optimized and dedicated method that runs much faster than
+ * sequence of relevant Jolokia operations (LIST+EXEC with maxDepth=7).
+ * @return
+ */
+ Map list() throws Exception;
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/osgi/OsgiMBeanDetector.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/osgi/OsgiMBeanDetector.java"
new file mode 100755
index 0000000..f41ef28
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/osgi/OsgiMBeanDetector.java"
@@ -0,0 +1,60 @@
+package io.hawt.osgi;
+
+import org.jolokia.backend.executor.MBeanServerExecutor;
+import org.jolokia.detector.ServerDetector;
+import org.jolokia.detector.ServerHandle;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.util.tracker.ServiceTracker;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import java.lang.instrument.Instrumentation;
+import java.util.Set;
+
+public class OsgiMBeanDetector implements ServerDetector {
+
+ public OsgiMBeanDetector() {
+ }
+
+ @Override
+ public ServerHandle detect(MBeanServerExecutor pMBeanServerExecutor) {
+ return null;
+ }
+
+ @Override
+ public void addMBeanServers(Set pMBeanServers) {
+ BundleContext context = null;
+ try {
+ Bundle bundle = FrameworkUtil.getBundle(getClass());
+ context = bundle != null ? bundle.getBundleContext() : null;
+ } catch (Throwable t) {
+ // Ignore
+ }
+ if (context != null) {
+ ServiceTracker tracker = new ServiceTracker<>(context, MBeanServer.class, null);
+ tracker.open();
+ MBeanServer server = null;
+ for (int i = 0; i < 1000; i++) {
+ server = tracker.getService();
+ if (server != null) {
+ break;
+ }
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ if (server != null) {
+ pMBeanServers.add(server);
+ }
+ }
+ }
+
+ @Override
+ public void jvmAgentStartup(Instrumentation instrumentation) {
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthHelpers.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthHelpers.java"
new file mode 100755
index 0000000..7bc11f7
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthHelpers.java"
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.system;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import javax.security.auth.Subject;
+
+import io.hawt.web.auth.LoginServlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helpers for authentication and authorization.
+ */
+public class AuthHelpers {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(LoginServlet.class);
+
+ public static final List KNOWN_PRINCIPALS = Arrays.asList(
+ "UserPrincipal", "KeycloakPrincipal", "JAASPrincipal", "SimplePrincipal");
+
+ public static String getUsername(Subject subject) {
+ Set principals = subject.getPrincipals();
+
+ String username = null;
+
+ if (principals != null) {
+ for (Principal principal : principals) {
+ String principalClass = principal.getClass().getSimpleName();
+ if (KNOWN_PRINCIPALS.contains(principalClass)) {
+ username = principal.getName();
+ LOG.debug("Username in principal: {}", username);
+ }
+ }
+ }
+
+ return username;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthInfo.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthInfo.java"
new file mode 100755
index 0000000..abd1c78
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthInfo.java"
@@ -0,0 +1,17 @@
+package io.hawt.system;
+
+import io.hawt.util.Strings;
+
+/**
+ * Authentication information that represents a set of user name and password.
+ */
+public class AuthInfo {
+
+ public String username;
+ public String password;
+
+ public boolean isSet() {
+ return Strings.isNotBlank(username) && Strings.isNotBlank(password);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthenticateResult.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthenticateResult.java"
new file mode 100755
index 0000000..cf7acb5
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/AuthenticateResult.java"
@@ -0,0 +1,10 @@
+package io.hawt.system;
+
+/**
+ * Authentication result
+ */
+public enum AuthenticateResult {
+ AUTHORIZED,
+ NOT_AUTHORIZED,
+ NO_CREDENTIALS
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/Authenticator.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/Authenticator.java"
new file mode 100755
index 0000000..3f824da
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/Authenticator.java"
@@ -0,0 +1,321 @@
+package io.hawt.system;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AccountException;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletRequest;
+
+import io.hawt.web.auth.AuthenticationConfiguration;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.karaf.jaas.boot.principal.ClientPrincipal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * To perform authentication using JAAS using the {@link LoginContext} for the choosen realm.
+ */
+public class Authenticator {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(Authenticator.class);
+
+ public static final String HEADER_AUTHORIZATION = "Authorization";
+ public static final String AUTHENTICATION_SCHEME_BASIC = "Basic";
+
+ private static Boolean websphereDetected;
+ private static Method websphereGetGroupsMethod;
+
+ public static void extractAuthInfo(String authHeader, BiConsumer callback) {
+ authHeader = authHeader.trim();
+ String[] parts = authHeader.split(" ");
+ if (parts.length != 2) {
+ return;
+ }
+
+ String authType = parts[0];
+ String authInfo = parts[1];
+
+ if (authType.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
+ String decoded = new String(Base64.decodeBase64(authInfo));
+ int delimiter = decoded.indexOf(':');
+ if (delimiter < 0) {
+ return;
+ }
+ String user = decoded.substring(0, delimiter);
+ String password = decoded.substring(delimiter + 1);
+ callback.accept(user, password);
+ }
+ }
+
+ public static void logout(AuthenticationConfiguration authConfiguration, Subject subject) {
+ try {
+ LoginContext loginContext = new LoginContext(authConfiguration.getRealm(), subject);
+ loginContext.logout();
+ } catch (Exception e) {
+ LOG.warn("Error occurred while logging out", e);
+ }
+ }
+
+ public static AuthenticateResult authenticate(AuthenticationConfiguration authConfiguration,
+ HttpServletRequest request, Consumer callback) {
+
+ String authHeader = request.getHeader(HEADER_AUTHORIZATION);
+
+ if (authHeader == null || authHeader.equals("")) {
+ return AuthenticateResult.NO_CREDENTIALS;
+ }
+
+ AuthInfo info = new AuthInfo();
+
+ extractAuthInfo(authHeader, (userName, password) -> {
+ info.username = userName;
+ info.password = password;
+ });
+
+ if (info.username == null || info.username.equals("public")) {
+ return AuthenticateResult.NO_CREDENTIALS;
+ }
+
+ if (info.isSet()) {
+ return authenticate(authConfiguration, request, info.username, info.password, callback);
+ }
+
+ return AuthenticateResult.NO_CREDENTIALS;
+ }
+
+ public static AuthenticateResult authenticate(AuthenticationConfiguration authConfiguration,
+ HttpServletRequest request,
+ String username, String password, Consumer callback) {
+ Subject subject = doAuthenticate(
+ request,
+ authConfiguration.getRealm(),
+ authConfiguration.getRole(),
+ authConfiguration.getRolePrincipalClasses(),
+ authConfiguration.getConfiguration(),
+ username,
+ password);
+ if (subject == null) {
+ return AuthenticateResult.NOT_AUTHORIZED;
+ }
+
+ if (callback != null) {
+ try {
+ callback.accept(subject);
+ } catch (Exception e) {
+ LOG.warn("Failed to execute privileged action:", e);
+ }
+ }
+
+ return AuthenticateResult.AUTHORIZED;
+ }
+
+ private static Subject doAuthenticate(HttpServletRequest request, String realm, String role, String rolePrincipalClasses, Configuration configuration,
+ final String username, final String password) {
+ try {
+
+ LOG.debug("doAuthenticate[realm={}, role={}, rolePrincipalClasses={}, configuration={}, username={}, password={}]",
+ realm, role, rolePrincipalClasses, configuration, username, "******");
+
+ Subject subject = new Subject();
+ try {
+ String addr = request.getRemoteHost() + ":" + request.getRemotePort();
+ subject.getPrincipals().add(new ClientPrincipal("hawtio", addr));
+ } catch (Throwable t) {
+ // ignore
+ }
+ CallbackHandler handler = new AuthenticationCallbackHandler(username, password);
+
+ // call the constructor with or without the configuration as it behaves differently
+ LoginContext loginContext;
+ if (configuration != null) {
+ loginContext = new LoginContext(realm, subject, handler, configuration);
+ } else {
+ loginContext = new LoginContext(realm, subject, handler);
+ }
+
+ loginContext.login();
+
+ if (role == null || role.equals("")) {
+ LOG.debug("Skipping role check, no role configured");
+ return subject;
+ }
+
+ if (role.equals("*")) {
+ LOG.debug("Skipping role check, all roles allowed");
+ return subject;
+ }
+
+ boolean found;
+ if (isRunningOnWebsphere(subject)) {
+ found = checkIfSubjectHasRequiredRoleOnWebsphere(subject, role);
+ } else {
+ if (rolePrincipalClasses == null || rolePrincipalClasses.equals("")) {
+ LOG.debug("Skipping role check, no rolePrincipalClasses configured");
+ return subject;
+ }
+
+ found = checkIfSubjectHasRequiredRole(subject, role, rolePrincipalClasses);
+ }
+
+ if (!found) {
+ LOG.debug("User {} does not have the required role {}", username, role);
+ return null;
+ }
+
+ return subject;
+
+ } catch (AccountException e) {
+ LOG.warn("Account failure", e);
+ } catch (LoginException e) {
+ LOG.warn("Login failed due to: {}", e.getMessage());
+ LOG.debug("Failed stacktrace:", e);
+ }
+
+ return null;
+ }
+
+ private static boolean checkIfSubjectHasRequiredRole(Subject subject,
+ String role, String rolePrincipalClasses) {
+ String[] roleArray = role.split(",");
+ String[] rolePrincipalClazzes = rolePrincipalClasses.split(",");
+ boolean found = false;
+ for (String clazz : rolePrincipalClazzes) {
+ LOG.debug("Looking for rolePrincipalClass: {}", clazz);
+ for (Principal p : subject.getPrincipals()) {
+ LOG.debug("Checking principal, classname: {} toString: {}", p.getClass().getName(), p);
+ if (!p.getClass().getName().equals(clazz.trim())) {
+ LOG.debug("principal class {} doesn't match {}, continuing", p.getClass().getName(), clazz.trim());
+ continue;
+ }
+ for (String r : roleArray) {
+ if (r == null || !p.getName().equals(r.trim())) {
+ LOG.debug("role {} doesn't match {}, continuing", p.getName(), r);
+ continue;
+ }
+ LOG.debug("Matched role and role principal class");
+ found = true;
+ break;
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+
+ }
+ return found;
+ }
+
+ private static boolean isRunningOnWebsphere(Subject subject) {
+ if (websphereDetected == null) {
+ boolean onWebsphere = false;
+ for (Principal p : subject.getPrincipals()) {
+ LOG.trace("Checking principal for IBM specific interfaces: {}", p);
+ onWebsphere = implementsInterface(p, "com.ibm.websphere.security.auth.WSPrincipal");
+ }
+ LOG.trace("Checking if we are running using a IBM Websphere specific LoginModule: {}", onWebsphere);
+ websphereDetected = onWebsphere;
+ }
+ return websphereDetected;
+ }
+
+ private static boolean checkIfSubjectHasRequiredRoleOnWebsphere(Subject subject, String role) {
+ LOG.debug("Running on websphere: checking if the Role {} is in the set of groups in WSCredential", role);
+ for (final Object cred : subject.getPublicCredentials()) {
+ LOG.debug("Checking credential {} if it is a WebSphere specific WSCredential containing group info", cred);
+ if (implementsInterface(cred, "com.ibm.websphere.security.cred.WSCredential")) {
+ try {
+ Method groupsMethod = getWebSphereGetGroupsMethod(cred);
+ @SuppressWarnings("unchecked") final List groups = (List) groupsMethod.invoke(cred);
+
+ if (groups != null) {
+ LOG.debug("Found a total of {} groups in the IBM WebSphere Credentials", groups.size());
+
+ for (Object group : groups) {
+ LOG.debug("Matching IBM Websphere group name {} to required role {}", group, role);
+
+ String[] roleArray = role.split(",");
+ for (String r : roleArray) {
+ if (r.equals(group.toString())) {
+ LOG.debug("Required role {} found in IBM WebSphere specific credentials", r);
+ return true;
+ } else {
+ LOG.debug("role {} doesn't match {}, continuing", r, group.toString());
+ }
+ }
+ }
+ } else {
+ LOG.debug("The IBM Websphere groups list is null");
+ }
+
+ } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ // ignored
+ LOG.debug("Caught exception trying to read groups from WebSphere specific WSCredentials class", e);
+ }
+ }
+ }
+ return false;
+ }
+
+ private static Method getWebSphereGetGroupsMethod(final Object cred) throws NoSuchMethodException {
+ if (websphereGetGroupsMethod == null) {
+ websphereGetGroupsMethod = cred.getClass().getMethod("getGroupIds");
+ }
+ return websphereGetGroupsMethod;
+ }
+
+ private static boolean implementsInterface(Object o, String interfaceName) {
+ boolean implementsIf = false;
+ for (Class> pif : o.getClass().getInterfaces()) {
+ LOG.trace("Checking interface {} if it matches {}", pif, interfaceName);
+ if (pif.getName().equals(interfaceName)) {
+ implementsIf = true;
+ break;
+ }
+ }
+ return implementsIf;
+ }
+
+ private static final class AuthenticationCallbackHandler implements CallbackHandler {
+
+ private final String username;
+ private final String password;
+
+ private AuthenticationCallbackHandler(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ for (Callback callback : callbacks) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Callback type {} -> {}", callback.getClass(), callback);
+ }
+ if (callback instanceof NameCallback) {
+ ((NameCallback) callback).setName(username);
+ } else if (callback instanceof PasswordCallback) {
+ ((PasswordCallback) callback).setPassword(password.toCharArray());
+ } else {
+ LOG.debug("Unknown callback class [" + callback.getClass().getName() + "]");
+ }
+ }
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/ConfigManager.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/ConfigManager.java"
new file mode 100755
index 0000000..4aa36ea
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/ConfigManager.java"
@@ -0,0 +1,105 @@
+package io.hawt.system;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.function.Function;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.servlet.ServletContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Configuration manager that provides hawtio configuration properties.
+ */
+public class ConfigManager {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(ConfigManager.class);
+
+ public static final String CONFIG_MANAGER = "ConfigManager";
+
+ private Context envContext = null;
+
+ private Function propertyResolver;
+
+ public ConfigManager() {
+ this.propertyResolver = ConfigManager::getHawtioSystemProperty;
+ }
+
+ public ConfigManager(final Function propertyResolver) {
+ Objects.requireNonNull(propertyResolver);
+
+ // System properties must always have priority
+ this.propertyResolver = x -> getProperty(x, ConfigManager::getHawtioSystemProperty, propertyResolver);
+ }
+
+ public void init(ServletContext servletContext) {
+ if (Boolean.parseBoolean(getHawtioSystemProperty(HawtioProperty.FORCE_PROPERTIES))) {
+ LOG.info("Forced using system properties");
+ return;
+ }
+
+ try {
+ envContext = (Context) new InitialContext().lookup("java:comp/env");
+ LOG.info("Configuration will be discovered via JNDI");
+ } catch (NamingException e) {
+ LOG.debug("Failed to look up environment context: {}", e.getMessage());
+ LOG.info("Configuration will be discovered via system properties");
+ }
+ }
+
+ public void destroy() {
+ if (envContext != null) {
+ try {
+ envContext.close();
+ } catch (NamingException e) {
+ // ignore...
+ }
+ envContext = null;
+ }
+ }
+
+ public String get(String name, String defaultValue) {
+ String answer = null;
+ if (envContext != null) {
+ try {
+ answer = (String) envContext.lookup("hawtio/" + name);
+ } catch (Exception e) {
+ // ignore...
+ }
+ }
+
+ if (answer == null) {
+ answer = this.propertyResolver.apply(name);
+ }
+
+ if (answer == null) {
+ answer = defaultValue;
+ }
+
+ LOG.debug("Property {} is set to value {}", name, answer);
+ return answer;
+ }
+
+ public boolean getBoolean(String name, boolean defaultValue) {
+ return Boolean.parseBoolean(get(name, Boolean.toString(defaultValue)));
+ }
+
+ private static String getHawtioSystemProperty(String name) {
+ return System.getProperty("hawtio." + name);
+ }
+
+ @SafeVarargs
+ private static String getProperty(String name,
+ Function... propertyResolvers) {
+ return Arrays.stream(propertyResolvers)
+ .map(resolver -> resolver.apply(name))
+ .filter(result -> result != null)
+ .findFirst()
+ .orElse(null);
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/HawtioProperty.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/HawtioProperty.java"
new file mode 100755
index 0000000..da6bbb8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/HawtioProperty.java"
@@ -0,0 +1,23 @@
+package io.hawt.system;
+
+/**
+ * Hawtio property name constants.
+ */
+public final class HawtioProperty {
+
+ /**
+ * Boolean flag indicating whether JNDI configuration should be skipped in
+ * preference of system properties.
+ */
+ public static final String FORCE_PROPERTIES = "forceProperties";
+
+ /**
+ * The name of the servlet context attribute holding hawtio deployment path
+ * relative to the context root. By default when hawtio is launched in
+ * stand-alone mode, its path is assumed to be at the root of the servlet. But
+ * in certain scenarios this might not be the case. For example, when running
+ * under Spring Boot, actual hawtio path can potentially consist of servlet
+ * prefix, management context path as well as hawtio endpoint path.
+ */
+ public static final String SERVLET_PATH = "hawtioServletPath";
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/JmxHelpers.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/JmxHelpers.java"
new file mode 100755
index 0000000..a0ea45f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/JmxHelpers.java"
@@ -0,0 +1,26 @@
+package io.hawt.system;
+
+import javax.management.ObjectName;
+import java.util.Set;
+
+/**
+ * Helpers for JMX
+ */
+public class JmxHelpers {
+
+ public static ObjectName chooseMBean(Set mbeans) {
+ if (mbeans.size() == 1) {
+ return mbeans.iterator().next();
+ }
+ for (ObjectName mbean : mbeans) {
+ if (!isHawtioDummy(mbean.toString())) {
+ return mbean;
+ }
+ }
+ return null;
+ }
+
+ private static boolean isHawtioDummy(String name) {
+ return name.contains("HawtioDummy");
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/ProxyWhitelist.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/ProxyWhitelist.java"
new file mode 100755
index 0000000..74fe7ef
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/ProxyWhitelist.java"
@@ -0,0 +1,170 @@
+package io.hawt.system;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.regex.Pattern;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import io.hawt.util.Hosts;
+import io.hawt.util.Strings;
+import io.hawt.web.proxy.ProxyDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Whitelist manager for hawtio proxy.
+ *
+ * TODO: For now this implementation is heavily relying on Fabric v1, and should be rewritten to a more general form.
+ */
+public class ProxyWhitelist {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(ProxyWhitelist.class);
+
+ private static final String FABRIC_MBEAN = "io.fabric8:type=Fabric";
+
+ protected CopyOnWriteArraySet whitelist;
+ protected List regexWhitelist;
+ protected MBeanServer mBeanServer;
+ protected ObjectName fabricMBean;
+
+ public ProxyWhitelist(String whitelistStr) {
+ this(whitelistStr, true);
+ }
+
+ public ProxyWhitelist(String whitelistStr, boolean probeLocal) {
+ if (Strings.isBlank(whitelistStr)) {
+ whitelist = new CopyOnWriteArraySet<>();
+ regexWhitelist = Collections.emptyList();
+ } else {
+ whitelist = new CopyOnWriteArraySet<>(filterRegex(Strings.split(whitelistStr, ",")));
+ regexWhitelist = buildRegexWhitelist(Strings.split(whitelistStr, ","));
+ }
+
+ if (probeLocal) {
+ LOG.info("Probing local addresses ...");
+ initialiseWhitelist();
+ } else {
+ LOG.info("Probing local addresses disabled");
+ whitelist.add("localhost");
+ whitelist.add("127.0.0.1");
+ }
+ LOG.info("Initial proxy whitelist: {}", whitelist);
+
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ try {
+ fabricMBean = new ObjectName(FABRIC_MBEAN);
+ } catch (MalformedObjectNameException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected List filterRegex(List whitelist) {
+ List result = new ArrayList<>();
+
+ for (String element : whitelist) {
+ if (!element.startsWith("r:")) {
+ result.add(element);
+ }
+ }
+
+ return result;
+ }
+
+ protected List buildRegexWhitelist(List whitelist) {
+ List patterns = new ArrayList<>();
+
+ for (String element : whitelist) {
+ if (element.startsWith("r:")) {
+ String regex = element.substring(2);
+ patterns.add(Pattern.compile(regex));
+ }
+ }
+
+ return patterns;
+ }
+
+ protected void initialiseWhitelist() {
+ Map> localAddresses = Hosts.getNetworkInterfaceAddresses(true);
+ for (Set addresses : localAddresses.values()) {
+ for (InetAddress address : addresses) {
+ whitelist.add(address.getHostAddress());
+ whitelist.add(address.getHostName());
+ whitelist.add(address.getCanonicalHostName());
+ }
+ }
+ }
+
+ public boolean isAllowed(ProxyDetails details) {
+ if (details.isAllowed(whitelist)) {
+ return true;
+ }
+
+ // Update whitelist and check again
+ LOG.debug("Updating proxy whitelist: {}, {}", whitelist, details);
+ if (update() && details.isAllowed(whitelist)) {
+ return true;
+ }
+
+ // test against the regex as last resort
+ if (details.isAllowed(regexWhitelist)) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ public boolean update() {
+ if (!mBeanServer.isRegistered(fabricMBean)) {
+ LOG.debug("Whitelist MBean not available");
+ return false;
+ }
+
+ Set newWhitelist = invokeMBean();
+ int previousSize = whitelist.size();
+ whitelist.addAll(newWhitelist);
+ if (whitelist.size() == previousSize) {
+ LOG.debug("No new proxy whitelist to update");
+ return false;
+ } else {
+ LOG.info("Updated proxy whitelist: {}", whitelist);
+ return true;
+ }
+ }
+
+ protected Set invokeMBean() {
+ Set list = new HashSet<>();
+ try {
+ @SuppressWarnings("unchecked")
+ List> containers = (List>) mBeanServer.invoke(fabricMBean,
+ "containers",
+ new Object[] { Arrays.asList("localHostname", "localIp", "manualIp", "publicHostname", "publicIp") },
+ new String[] { List.class.getName() });
+ LOG.debug("Returned containers from MBean: {}", containers);
+ for (Map container : containers) {
+ for (Object value : container.values()) {
+ if (value != null && Strings.isNotBlank(value.toString())) {
+ list.add(value.toString());
+ }
+ }
+ }
+ LOG.debug("Extracted whitelist: {}", list);
+ } catch (InstanceNotFoundException | MBeanException | ReflectionException e) {
+ LOG.error("Invocation to whitelist MBean failed: " + e.getMessage(), e);
+ }
+ return list;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/RBACMBeanInvoker.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/RBACMBeanInvoker.java"
new file mode 100755
index 0000000..d118589
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/RBACMBeanInvoker.java"
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.system;
+
+import java.lang.management.ManagementFactory;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.security.auth.Subject;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Cached MBean server invoker for {@link RBACRestrictor}.
+ */
+public class RBACMBeanInvoker {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(RBACMBeanInvoker.class);
+
+ /**
+ * The length of time (in minutes) an entry in canInvokeCache is valid after creation
+ */
+ private static long CAN_INVOKE_CACHE_DURATION = 10;
+
+ /**
+ * The length of time (in minutes) an entry in mbeanInfoCache is valid after creation
+ */
+ private static long MBEAN_INFO_CACHE_DURATION = 10;
+
+ protected MBeanServer mBeanServer;
+ protected ObjectName securityMBean;
+
+ protected LoadingCache canInvokeCache;
+ protected LoadingCache> mbeanInfoCache;
+
+ protected class CanInvokeKey {
+ protected String username;
+ protected ObjectName objectName;
+ protected String operation;
+
+ protected CanInvokeKey(String username, ObjectName objectName, String operation) {
+ this.username = username;
+ this.objectName = objectName;
+ this.operation = operation;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CanInvokeKey)) {
+ return false;
+ }
+ CanInvokeKey key = (CanInvokeKey) obj;
+ return Objects.equals(username, key.username)
+ && Objects.equals(objectName, key.objectName)
+ && Objects.equals(operation, key.operation);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(username, objectName, operation);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s{username=%s, objectName=%s, operation=%s}",
+ getClass().getSimpleName(),
+ Objects.toString(username),
+ Objects.toString(objectName),
+ Objects.toString(operation));
+ }
+ }
+
+ public RBACMBeanInvoker() {
+ initSecurityMBean();
+ initCaches();
+ }
+
+ protected void initSecurityMBean() {
+ this.mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ Set mbeans = new HashSet<>();
+ try {
+ mbeans = mBeanServer.queryNames(new ObjectName("*:type=security,area=jmx,*"), null);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found JMXSecurity MBeans: {}", mbeans);
+ }
+ } catch (MalformedObjectNameException e) {
+ LOG.error(e.getMessage(), e);
+ }
+ if (mbeans.isEmpty()) {
+ LOG.info("Didn't discover any JMXSecurity MBeans, role based access control is disabled");
+ this.securityMBean = null;
+ return;
+ }
+
+ ObjectName chosen = JmxHelpers.chooseMBean(mbeans);
+ LOG.info("Using MBean [{}] for role based access control", chosen);
+ this.securityMBean = chosen;
+ }
+
+ protected void initCaches() {
+ this.canInvokeCache = CacheBuilder.newBuilder()
+ .expireAfterWrite(CAN_INVOKE_CACHE_DURATION, TimeUnit.MINUTES)
+ .build(new CacheLoader() {
+ @Override
+ public Boolean load(CanInvokeKey key) throws Exception {
+ LOG.debug("Do invoking canInvoke() for {}", key);
+ return doCanInvoke(key.objectName, key.operation);
+ }
+ });
+ this.mbeanInfoCache = CacheBuilder.newBuilder()
+ .expireAfterWrite(MBEAN_INFO_CACHE_DURATION, TimeUnit.MINUTES)
+ .build(new CacheLoader>() {
+ @Override
+ public Map load(ObjectName objectName) throws Exception {
+ LOG.debug("Do loading MBean attributes for {}", objectName);
+ return loadMBeanAttributes(objectName);
+ }
+ });
+ }
+
+ protected boolean doCanInvoke(ObjectName objectName, String operation) throws Exception {
+ List argTypes = new ArrayList<>();
+ String opName = parseOperation(operation, argTypes);
+ // The order of properties in an object name is critical for Karaf, so we cannot use
+ // ObjectName.getCanonicalName() to get the object name string here
+ // See: https://issues.apache.org/jira/browse/KARAF-4600
+ Object[] params = new Object[] { objectName.toString(), opName, argTypes.toArray(new String[0]) };
+ String[] signature = new String[] { String.class.getName(), String.class.getName(), String[].class.getName() };
+ return (boolean) mBeanServer.invoke(securityMBean, "canInvoke", params, signature);
+ }
+
+ private String parseOperation(String operation, List argTypes) {
+ operation = operation.trim();
+ int index = operation.indexOf('(');
+ if (index < 0) {
+ return operation;
+ }
+
+ String args = operation.substring(index + 1, operation.length() - 1);
+ for (String arg : args.split(",")) {
+ if (!"".equals(arg)) {
+ argTypes.add(arg);
+ }
+ }
+
+ return operation.substring(0, index);
+ }
+
+ private static void logMBeanError(Exception e) {
+ if (e instanceof InstanceNotFoundException) {
+ LOG.info("Instance not found: {}", e.getMessage());
+ } else if (e.getCause() instanceof InstanceNotFoundException) {
+ LOG.info("Instance not found: {}", e.getCause().getMessage());
+ } else {
+ LOG.error("Error while invoking JMXSecurity MBean: " + e.getMessage(), e);
+ }
+ }
+
+ protected Map loadMBeanAttributes(ObjectName objectName) throws Exception {
+ MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(objectName);
+ Map answer = new HashMap<>();
+ for (MBeanAttributeInfo info : mBeanInfo.getAttributes()) {
+ answer.put(info.getName(), info);
+ }
+ return answer;
+ }
+
+ public boolean canInvoke(ObjectName objectName, String operation) {
+ if (this.securityMBean == null) {
+ // JMXSecurity MBean is not found, thus RBAC is disabled
+ return true;
+ }
+
+ AccessControlContext acc = AccessController.getContext();
+ Subject subject = Subject.getSubject(acc);
+ try {
+ if (subject != null) {
+ String username = AuthHelpers.getUsername(subject);
+ return canInvokeCache.get(new CanInvokeKey(username, objectName, operation));
+ } else {
+ // For now, let's bypass the caching and directly invoke the security MBean if
+ // subject is not available (which could happen on some platforms other than Karaf)
+ LOG.debug("Subject not available, directly invoking canInvoke(): {}, {}", objectName, operation);
+ return doCanInvoke(objectName, operation);
+ }
+ } catch (Exception e) {
+ logMBeanError(e);
+ return false;
+ }
+ }
+
+ public boolean isReadAllowed(ObjectName objectName, String attribute) {
+ if (this.securityMBean == null) {
+ // JMXSecurity MBean is not found, thus RBAC is disabled
+ return true;
+ }
+
+ try {
+ MBeanAttributeInfo info = mbeanInfoCache.get(objectName).get(attribute);
+ if (info == null) {
+ LOG.error("Attribute '{}' not found for MBean '{}'", attribute, objectName);
+ return false;
+ }
+ return canInvoke(objectName, getAccessor(info, false));
+ } catch (Exception e) {
+ logMBeanError(e);
+ return false;
+ }
+ }
+
+ public boolean isWriteAllowed(ObjectName objectName, String attribute) {
+ if (this.securityMBean == null) {
+ // JMXSecurity MBean is not found, thus RBAC is disabled
+ return true;
+ }
+
+ try {
+ MBeanAttributeInfo info = mbeanInfoCache.get(objectName).get(attribute);
+ if (info == null) {
+ LOG.error("Attribute '{}' not found for MBean '{}'", attribute, objectName);
+ return false;
+ }
+ return canInvoke(objectName, getAccessor(info, true));
+ } catch (Exception e) {
+ logMBeanError(e);
+ return false;
+ }
+ }
+
+ private String getAccessor(MBeanAttributeInfo attribute, boolean write) {
+ if (write) {
+ return String.format("set%s(%s)", attribute.getName(), attribute.getType());
+ } else {
+ return String.format("%s%s()", attribute.isIs() ? "is" : "get", attribute.getName());
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/RBACRestrictor.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/RBACRestrictor.java"
new file mode 100755
index 0000000..ca7b928
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/system/RBACRestrictor.java"
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2016 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.system;
+
+import java.io.IOException;
+import javax.management.ObjectName;
+
+import org.jolokia.config.ConfigKey;
+import org.jolokia.config.Configuration;
+import org.jolokia.restrictor.AllowAllRestrictor;
+import org.jolokia.restrictor.DenyAllRestrictor;
+import org.jolokia.restrictor.Restrictor;
+import org.jolokia.restrictor.RestrictorFactory;
+import org.jolokia.util.HttpMethod;
+import org.jolokia.util.NetworkUtil;
+import org.jolokia.util.RequestType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Jolokia restrictor that protects MBean server invocation inside Jolokia based on RBAC provided by
+ * {@link io.hawt.jmx.JMXSecurityMBean}.
+ */
+public class RBACRestrictor implements Restrictor {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(RBACRestrictor.class);
+
+ protected Restrictor delegate;
+ protected RBACMBeanInvoker mBeanInvoker;
+
+ public RBACRestrictor(Configuration config) {
+ initDelegate(config);
+ this.mBeanInvoker = new RBACMBeanInvoker();
+ }
+
+ protected void initDelegate(Configuration config) {
+ String location = NetworkUtil.replaceExpression(config.get(ConfigKey.POLICY_LOCATION));
+ try {
+ this.delegate = RestrictorFactory.lookupPolicyRestrictor(location);
+ if (this.delegate != null) {
+ LOG.debug("Delegate - Using policy access restrictor {}", location);
+ } else {
+ LOG.debug("Delegate - No policy access restrictor found, access to any MBean is allowed");
+ this.delegate = new AllowAllRestrictor();
+ }
+ } catch (IOException e) {
+ LOG.error("Delegate - Error while accessing access policy restrictor at " + location +
+ ". Denying all access to MBeans for security reasons. Exception: " + e, e);
+ this.delegate = new DenyAllRestrictor();
+ }
+ }
+
+ @Override
+ public boolean isOperationAllowed(ObjectName objectName, String operation) {
+ boolean allowed = delegate.isOperationAllowed(objectName, operation);
+ if (allowed) {
+ allowed = mBeanInvoker.canInvoke(objectName, operation);
+ }
+ LOG.debug("isOperationAllowed(objectName = {}, operation = {}) = {}",
+ objectName, operation, allowed);
+ return allowed;
+ }
+
+ @Override
+ public boolean isAttributeReadAllowed(ObjectName objectName, String attribute) {
+ boolean allowed = delegate.isAttributeReadAllowed(objectName, attribute);
+ if (allowed) {
+ allowed = mBeanInvoker.isReadAllowed(objectName, attribute);
+ }
+ LOG.debug("isAttributeReadAllowed(objectName = {}, attribute = {}) = {}",
+ objectName, attribute, allowed);
+ return allowed;
+ }
+
+ @Override
+ public boolean isAttributeWriteAllowed(ObjectName objectName, String attribute) {
+ boolean allowed = delegate.isAttributeWriteAllowed(objectName, attribute);
+ if (allowed) {
+ allowed = mBeanInvoker.isWriteAllowed(objectName, attribute);
+ }
+ LOG.debug("isAttributeWriteAllowed(objectName = {}, attribute = {}) = {}",
+ objectName, attribute, allowed);
+ return allowed;
+ }
+
+ @Override
+ public boolean isHttpMethodAllowed(HttpMethod method) {
+ boolean allowed = delegate.isHttpMethodAllowed(method);
+ LOG.trace("isHttpMethodAllowed(method = {}) = {}", method, allowed);
+ return allowed;
+ }
+
+ @Override
+ public boolean isTypeAllowed(RequestType type) {
+ boolean allowed = delegate.isTypeAllowed(type);
+ LOG.trace("isTypeAllowed(type = {}) = {}", type, allowed);
+ return allowed;
+ }
+
+ @Override
+ public boolean isRemoteAccessAllowed(String... hostOrAddress) {
+ boolean allowed = delegate.isRemoteAccessAllowed(hostOrAddress);
+ LOG.trace("isRemoteAccessAllowed(hostOrAddress = {}) = {}",
+ hostOrAddress, allowed);
+ return allowed;
+ }
+
+ @Override
+ public boolean isOriginAllowed(String origin, boolean strictCheck) {
+ boolean allowed = delegate.isOriginAllowed(origin, strictCheck);
+ LOG.trace("isOriginAllowed(origin = {}, strictCheck = {}) = {}",
+ origin, strictCheck, allowed);
+ return allowed;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/ForbiddenReason.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/ForbiddenReason.java"
new file mode 100755
index 0000000..fcdf132
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/ForbiddenReason.java"
@@ -0,0 +1,6 @@
+package io.hawt.web;
+
+public enum ForbiddenReason {
+ NONE,
+ HOST_NOT_ALLOWED
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/ServletHelpers.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/ServletHelpers.java"
new file mode 100755
index 0000000..d0f8a66
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/ServletHelpers.java"
@@ -0,0 +1,209 @@
+package io.hawt.web;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.AttributeNotFoundException;
+import javax.servlet.http.HttpServletResponse;
+
+import io.hawt.system.Authenticator;
+import io.hawt.util.IOHelper;
+import org.jolokia.converter.Converters;
+import org.jolokia.converter.json.JsonConvertOptions;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helpers for servlet
+ */
+public class ServletHelpers {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(ServletHelpers.class);
+
+ private static final String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+
+ public static void doForbidden(HttpServletResponse response) {
+ doForbidden(response, ForbiddenReason.NONE);
+ }
+
+ public static void doForbidden(HttpServletResponse response, ForbiddenReason reason) {
+ try {
+ byte[] contentBytes = new JSONObject().put("reason", reason).toString().getBytes("UTF-8");
+ response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+ response.setContentType("application/json");
+ response.setContentLength(contentBytes.length);
+ response.getOutputStream().write(contentBytes);
+ response.flushBuffer();
+ } catch (IOException ioe) {
+ LOG.debug("Failed to send forbidden response: {}", ioe);
+ }
+ }
+
+ public static void doAuthPrompt(String realm, HttpServletResponse response) {
+ // request authentication
+ try {
+ response.setHeader(HEADER_WWW_AUTHENTICATE, Authenticator.AUTHENTICATION_SCHEME_BASIC + " realm=\"" + realm + "\"");
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentLength(0);
+ response.flushBuffer();
+ } catch (IOException ioe) {
+ LOG.debug("Failed to send auth response: {}", ioe);
+ }
+ }
+
+ public static JSONObject readObject(BufferedReader reader) throws IOException {
+ String data = IOHelper.readFully(reader);
+ return new JSONObject(data);
+ }
+
+ public static void writeEmpty(PrintWriter out) {
+ out.write("{}");
+ out.flush();
+ out.close();
+ }
+
+ public static void writeObject(Converters converters, JsonConvertOptions options, PrintWriter out, Object data) {
+ Object result = null;
+
+ try {
+ result = converters.getToJsonConverter().convertToJson(data, null, options);
+ } catch (AttributeNotFoundException e) {
+ LOG.warn("Failed to convert object to json", e);
+ }
+
+ if (result != null) {
+ out.write(result.toString());
+ out.flush();
+ out.close();
+ } else {
+ writeEmpty(out);
+ }
+ }
+
+ public static Map populateTableMapForXl(List listEntry) {
+ listEntry = flatten(listEntry);
+ Map xlData = new HashMap<>();
+ Set columns = getColumns(listEntry);
+ List rowsData = getRowsData(listEntry, columns);
+
+ xlData.put("columns", columns);
+ xlData.put("rows", rowsData);
+ return xlData;
+ }
+
+
+ public static Map populateErrorTableMapForXl(List listEntry) {
+ listEntry = flatten(listEntry);
+
+ Map xlData = new HashMap<>();
+ Set columns = new HashSet<>();
+ columns.add("Error Message");
+ List rowsData = new ArrayList();
+ for (Object o : listEntry) {
+ Map keyValuePairs = new HashMap<>();
+ keyValuePairs.put(columns.toArray()[0].toString(), removeNoisyString(o.toString()));
+ rowsData.add(keyValuePairs);
+ }
+ xlData.put("columns", columns);
+ xlData.put("rows", rowsData);
+ return xlData;
+ }
+
+ private static Set getColumns(List listEntry) {
+ Set set = new HashSet();
+ for (Object o : listEntry) {
+ if (o instanceof JSONObject) {
+ set.addAll(((JSONObject) o).keySet());
+ }
+ }
+ return set;
+ }
+
+
+ private static List getRowsData(List listEntry, Set columns) {
+ List> list = new ArrayList<>();
+ for (Object o : listEntry) {
+ Map keyValuePairs = new HashMap<>();
+ if (o instanceof JSONObject) {
+ JSONObject jsonObject = (JSONObject) o;
+ for (Object column : columns) {
+ Object value = removeNoisyString(jsonObject.get(column.toString()));
+ keyValuePairs.put(column.toString(), value);
+ }
+ }
+ list.add(keyValuePairs);
+ }
+ return list;
+ }
+
+
+ public static String generateCsvString(Map xlData) {
+ int idx1 = 0, idx2 = 0;
+ StringBuffer buffer = new StringBuffer();
+ Set columns = (Set) xlData.get("columns");
+ List rows = (List) xlData.get("rows");
+ for (Object column : columns) {
+ buffer.append(wrapWithDoubleQuotes(column.toString()));
+ buffer = appendComma(buffer, columns.size(), idx1);
+ idx1++;
+ }
+ idx1 = 0;
+
+ buffer.append("\n");
+ for (Object row : rows) {
+ Map keyValuePair = (Map) row;
+ for (Object column : columns) {
+ buffer.append(wrapWithDoubleQuotes(keyValuePair.get(column.toString()).toString()));
+ buffer = appendComma(buffer, columns.size(), idx2);
+ idx2++;
+ }
+ idx2 = 0;
+ buffer.append("\n");
+ }
+ return buffer.toString();
+ }
+
+ private static String wrapWithDoubleQuotes(String string) {
+ return "\"" + string + "\"";
+ }
+
+ private static StringBuffer appendComma(StringBuffer buffer, int size, int index) {
+ return (size == (index + 1)) ? buffer : buffer.append(",");
+ }
+
+ public static List flatten(List list) {
+ List tempList = new ArrayList();
+ for (Object o : list) {
+ if (o instanceof Collection) {
+ tempList.addAll((Collection) o);
+ } else tempList.add(o);
+ }
+ return tempList;
+ }
+
+ public static Set flatten(Set set) {
+ Set tempSet = new HashSet();
+ for (Object o : tempSet) {
+ if (o instanceof Collection) {
+ tempSet.addAll((Collection) o);
+ } else tempSet.add(o);
+ }
+ return tempSet;
+ }
+
+ public static String removeNoisyString(Object value) {
+ String string = "";
+ if (value != null) {
+ string = (value.toString().contains("@reference")) ? "" : value.toString();
+ }
+ return string;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationConfiguration.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationConfiguration.java"
new file mode 100755
index 0000000..2c0f10d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationConfiguration.java"
@@ -0,0 +1,217 @@
+package io.hawt.web.auth;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.security.auth.login.Configuration;
+import javax.servlet.ServletContext;
+
+import io.hawt.system.ConfigManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuthenticationConfiguration {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(AuthenticationConfiguration.class);
+
+ public static final String LOGIN_URL = "/auth/login";
+ public static final String[] UNSECURED_PATHS = {"/auth", "/css", "/fonts", "/img", "/js", "/hawtconfig.json",
+ "/jolokia", "/keycloak", "/oauth", "/user", "/login.html"};
+
+ // Configuration properties
+ public static final String AUTHENTICATION_ENABLED = "authenticationEnabled";
+ public static final String NO_CREDENTIALS_401 = "noCredentials401";
+ public static final String REALM = "realm";
+ public static final String ROLE = "role";
+ public static final String ROLES = "roles";
+ public static final String ROLE_PRINCIPAL_CLASSES = "rolePrincipalClasses";
+ public static final String AUTHENTICATION_CONTAINER_DISCOVERY_CLASSES = "authenticationContainerDiscoveryClasses";
+ public static final String KEYCLOAK_ENABLED = "keycloakEnabled";
+
+ // JVM system properties
+ public static final String HAWTIO_AUTHENTICATION_ENABLED = "hawtio." + AUTHENTICATION_ENABLED;
+ public static final String HAWTIO_NO_CREDENTIALS_401 = "hawtio." + NO_CREDENTIALS_401;
+ public static final String HAWTIO_REALM = "hawtio." + REALM;
+ public static final String HAWTIO_ROLE = "hawtio.role";
+ public static final String HAWTIO_ROLES = "hawtio.roles";
+ public static final String HAWTIO_ROLE_PRINCIPAL_CLASSES = "hawtio." + ROLE_PRINCIPAL_CLASSES;
+ public static final String HAWTIO_AUTH_CONTAINER_DISCOVERY_CLASSES
+ = "hawtio." + AUTHENTICATION_CONTAINER_DISCOVERY_CLASSES;
+ public static final String HAWTIO_KEYCLOAK_ENABLED = "hawtio." + KEYCLOAK_ENABLED;
+
+ // ServletContext attributes
+ public static final String AUTHENTICATION_CONFIGURATION = "authenticationConfig";
+
+ public static final String DEFAULT_REALM = "karaf";
+ private static final String DEFAULT_KARAF_ROLES = "admin,manager,viewer";
+ public static final String DEFAULT_KARAF_ROLE_PRINCIPAL_CLASSES =
+ "org.apache.karaf.jaas.boot.principal.RolePrincipal,"
+ + "org.apache.karaf.jaas.modules.RolePrincipal,"
+ + "org.apache.karaf.jaas.boot.principal.GroupPrincipal";
+ public static final String TOMCAT_AUTH_CONTAINER_DISCOVERY =
+ "io.hawt.web.tomcat.TomcatAuthenticationContainerDiscovery";
+
+ private boolean enabled;
+ private boolean noCredentials401;
+ private String realm;
+ private String role;
+ private String rolePrincipalClasses;
+ private Configuration configuration;
+ private boolean keycloakEnabled;
+
+ public AuthenticationConfiguration(ServletContext servletContext) {
+ ConfigManager config = (ConfigManager) servletContext.getAttribute(ConfigManager.CONFIG_MANAGER);
+
+ String defaultRolePrincipalClasses = "";
+
+ if (System.getProperty("karaf.name") != null) {
+ defaultRolePrincipalClasses = DEFAULT_KARAF_ROLE_PRINCIPAL_CLASSES;
+ }
+
+ String authDiscoveryClasses = TOMCAT_AUTH_CONTAINER_DISCOVERY;
+
+ if (config != null) {
+ this.realm = config.get(REALM, DEFAULT_REALM);
+ // we have either role or roles
+ String roles = config.get(ROLE, null);
+ if (roles == null) {
+ roles = config.get(ROLES, null);
+ }
+ if (roles == null) {
+ // use default roles (karaf roles)
+ roles = DEFAULT_KARAF_ROLES;
+ }
+ this.role = roles;
+ this.rolePrincipalClasses = config.get(ROLE_PRINCIPAL_CLASSES, defaultRolePrincipalClasses);
+ this.enabled = config.getBoolean(AUTHENTICATION_ENABLED, true);
+ this.noCredentials401 = config.getBoolean(NO_CREDENTIALS_401, false);
+ this.keycloakEnabled = this.enabled && config.getBoolean(KEYCLOAK_ENABLED, false);
+
+ authDiscoveryClasses = config.get(AUTHENTICATION_CONTAINER_DISCOVERY_CLASSES, authDiscoveryClasses);
+ }
+
+ // JVM system properties can override always
+ if (System.getProperty(HAWTIO_AUTHENTICATION_ENABLED) != null) {
+ this.enabled = Boolean.getBoolean(HAWTIO_AUTHENTICATION_ENABLED);
+ }
+ if (System.getProperty(HAWTIO_NO_CREDENTIALS_401) != null) {
+ this.noCredentials401 = Boolean.getBoolean(HAWTIO_NO_CREDENTIALS_401);
+ }
+ if (System.getProperty(HAWTIO_REALM) != null) {
+ this.realm = System.getProperty(HAWTIO_REALM);
+ }
+ if (System.getProperty(HAWTIO_ROLE) != null) {
+ this.role = System.getProperty(HAWTIO_ROLE);
+ }
+ if (System.getProperty(HAWTIO_ROLES) != null) {
+ this.role = System.getProperty(HAWTIO_ROLES);
+ }
+ if (System.getProperty(HAWTIO_ROLE_PRINCIPAL_CLASSES) != null) {
+ this.rolePrincipalClasses = System.getProperty(HAWTIO_ROLE_PRINCIPAL_CLASSES);
+ }
+ if (System.getProperty(HAWTIO_KEYCLOAK_ENABLED) != null) {
+ this.keycloakEnabled = this.enabled && Boolean.getBoolean(HAWTIO_KEYCLOAK_ENABLED);
+ }
+ if (System.getProperty(HAWTIO_AUTH_CONTAINER_DISCOVERY_CLASSES) != null) {
+ authDiscoveryClasses = System.getProperty(HAWTIO_AUTH_CONTAINER_DISCOVERY_CLASSES);
+ }
+
+ if (this.enabled) {
+ List discoveries = getDiscoveries(authDiscoveryClasses);
+ for (AuthenticationContainerDiscovery discovery : discoveries) {
+ if (discovery.canAuthenticate(this)) {
+ LOG.info("Discovered container {} to use with hawtio authentication filter", discovery.getContainerName());
+ break;
+ }
+ }
+ }
+
+ if (this.enabled) {
+ LOG.info("Starting hawtio authentication filter, JAAS realm: \"{}\" authorized role(s): \"{}\" role principal classes: \"{}\"",
+ this.realm, this.role, this.rolePrincipalClasses);
+ } else {
+ LOG.info("Starting hawtio authentication filter, JAAS authentication disabled");
+ }
+ }
+
+ public static AuthenticationConfiguration getConfiguration(ServletContext servletContext) {
+ AuthenticationConfiguration authConfig = (AuthenticationConfiguration) servletContext.getAttribute(
+ AUTHENTICATION_CONFIGURATION);
+ if (authConfig == null) {
+ authConfig = new AuthenticationConfiguration(servletContext);
+ servletContext.setAttribute(AUTHENTICATION_ENABLED, authConfig.isEnabled());
+ servletContext.setAttribute(AUTHENTICATION_CONFIGURATION, authConfig);
+ }
+ return authConfig;
+ }
+
+ private static List getDiscoveries(String authDiscoveryClasses) {
+ List discoveries = new ArrayList<>();
+ if (authDiscoveryClasses == null || authDiscoveryClasses.trim().isEmpty()) {
+ return discoveries;
+ }
+
+ String[] discoveryClasses = authDiscoveryClasses.split(",");
+ for (String discoveryClass : discoveryClasses) {
+ try {
+ // Should have more clever classloading?
+ Class extends AuthenticationContainerDiscovery> clazz =
+ (Class extends AuthenticationContainerDiscovery>) AuthenticationConfiguration.class
+ .getClassLoader().loadClass(discoveryClass.trim());
+ AuthenticationContainerDiscovery discovery = clazz.newInstance();
+ discoveries.add(discovery);
+ } catch (Exception e) {
+ LOG.warn("Couldn't instantiate discovery " + discoveryClass, e);
+ }
+ }
+ return discoveries;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public boolean isNoCredentials401() {
+ return noCredentials401;
+ }
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public String getRolePrincipalClasses() {
+ return rolePrincipalClasses;
+ }
+
+ public void setRolePrincipalClasses(String rolePrincipalClasses) {
+ this.rolePrincipalClasses = rolePrincipalClasses;
+ }
+
+ public Configuration getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ public boolean isKeycloakEnabled() {
+ return keycloakEnabled;
+ }
+
+ @Override
+ public String toString() {
+ return "AuthenticationConfiguration[" +
+ "enabled=" + enabled +
+ ", noCredentials401=" + noCredentials401 +
+ ", realm='" + realm + '\'' +
+ ", role(s)='" + role + '\'' +
+ ", rolePrincipalClasses='" + rolePrincipalClasses + '\'' +
+ ", configuration=" + configuration +
+ ", keycloakEnabled=" + keycloakEnabled +
+ ']';
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationContainerDiscovery.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationContainerDiscovery.java"
new file mode 100755
index 0000000..51697e7
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationContainerDiscovery.java"
@@ -0,0 +1,23 @@
+package io.hawt.web.auth;
+
+/**
+ * SPI to allow various containers to discover and hook up needed configuration
+ * changes to {@link AuthenticationConfiguration} so hawtio {@link AuthenticationFilter}
+ * can integrate with the container easily.
+ */
+public interface AuthenticationContainerDiscovery {
+
+ /**
+ * Gets the container name such as Apache Tomcat, used for logging purpose
+ */
+ String getContainerName();
+
+ /**
+ * Whether the container can/should be used for authentication
+ *
+ * @param configuration the configuration option (muteable)
+ * @return true if the container is being used for authentication.
+ */
+ boolean canAuthenticate(AuthenticationConfiguration configuration);
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationFilter.java"
new file mode 100755
index 0000000..7344726
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/AuthenticationFilter.java"
@@ -0,0 +1,115 @@
+package io.hawt.web.auth;
+
+import io.hawt.system.AuthInfo;
+import io.hawt.system.AuthenticateResult;
+import io.hawt.system.Authenticator;
+import io.hawt.web.ServletHelpers;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * Filter for authentication. If the filter is enabled, then the login screen is shown.
+ */
+public class AuthenticationFilter implements Filter {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(AuthenticationFilter.class);
+
+ private AuthenticationConfiguration authConfiguration;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ authConfiguration = AuthenticationConfiguration.getConfiguration(filterConfig.getServletContext());
+ }
+
+ @Override
+ public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ String path = httpRequest.getServletPath();
+
+ LOG.debug("Handling request for path {}", path);
+
+ if (authConfiguration.getRealm() == null || authConfiguration.getRealm().equals("") || !authConfiguration.isEnabled()) {
+ LOG.debug("No authentication needed for path {}", path);
+ chain.doFilter(request, response);
+ return;
+ }
+
+ HttpSession session = httpRequest.getSession(false);
+ if (session != null) {
+ Subject subject = (Subject) session.getAttribute("subject");
+ // Connecting from another Hawtio may have a different user authentication, so
+ // let's check if the session user is the same as in the authorization header here
+ if (subject != null && validateSession(httpRequest, session, subject)) {
+ executeAs(request, response, chain, subject);
+ return;
+ }
+ }
+
+ LOG.debug("Doing authentication and authorization for path {}", path);
+
+ AuthenticateResult result = Authenticator.authenticate(
+ authConfiguration, httpRequest,
+ subject -> executeAs(request, response, chain, subject));
+
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ switch (result) {
+ case AUTHORIZED:
+ // request was executed using the authenticated subject, nothing more to do
+ break;
+ case NOT_AUTHORIZED:
+ ServletHelpers.doForbidden(httpResponse);
+ break;
+ case NO_CREDENTIALS:
+ if (authConfiguration.isNoCredentials401()) {
+ // return auth prompt 401
+ ServletHelpers.doAuthPrompt(authConfiguration.getRealm(), httpResponse);
+ } else {
+ // return forbidden 403 so the browser login does not popup
+ ServletHelpers.doForbidden(httpResponse);
+ }
+ break;
+ }
+ }
+
+ private boolean validateSession(HttpServletRequest request, HttpSession session, Subject subject) {
+ String authHeader = request.getHeader(Authenticator.HEADER_AUTHORIZATION);
+ AuthInfo info = new AuthInfo();
+ if (authHeader != null && !authHeader.equals("")) {
+ Authenticator.extractAuthInfo(authHeader, (userName, password) -> info.username = userName);
+ }
+ String sessionUser = (String) session.getAttribute("user");
+ if (info.username == null || info.username.equals(sessionUser)) {
+ LOG.debug("Session subject - {}", subject);
+ return true;
+ } else {
+ LOG.debug("User differs, re-authenticating: {} (request) != {} (session)", info.username, sessionUser);
+ session.invalidate();
+ return false;
+ }
+ }
+
+ private static void executeAs(final ServletRequest request, final ServletResponse response, final FilterChain chain, Subject subject) {
+ try {
+ Subject.doAs(subject, (PrivilegedExceptionAction) () -> {
+ chain.doFilter(request, response);
+ return null;
+ });
+ } catch (PrivilegedActionException e) {
+ LOG.info("Failed to invoke action " + ((HttpServletRequest) request).getPathInfo() + " due to:", e);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ LOG.info("Destroying hawtio authentication filter");
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LoginRedirectFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LoginRedirectFilter.java"
new file mode 100755
index 0000000..858eb85
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LoginRedirectFilter.java"
@@ -0,0 +1,69 @@
+package io.hawt.web.auth;
+
+import java.io.IOException;
+import java.util.Arrays;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Redirect to login page when authentication is enabled.
+ */
+public class LoginRedirectFilter implements Filter {
+
+ private AuthenticationConfiguration authConfiguration;
+
+ private final String[] unsecuredPaths;
+
+ private Redirector redirector = new Redirector();
+
+ public LoginRedirectFilter() {
+ this(AuthenticationConfiguration.UNSECURED_PATHS);
+ }
+
+ public LoginRedirectFilter(String[] unsecuredPaths) {
+ this.unsecuredPaths = unsecuredPaths;
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ authConfiguration = AuthenticationConfiguration.getConfiguration(filterConfig.getServletContext());
+ }
+
+ @Override
+ public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ HttpSession session = httpRequest.getSession(false);
+ String path = httpRequest.getServletPath();
+
+ if (authConfiguration.isEnabled() && !authConfiguration.isKeycloakEnabled()
+ && !isAuthenticated(session) && isSecuredPath(path)) {
+ redirector.doRedirect(httpRequest, httpResponse, AuthenticationConfiguration.LOGIN_URL);
+ } else {
+ chain.doFilter(request, response);
+ }
+ }
+
+ private boolean isAuthenticated(HttpSession session) {
+ return session != null && session.getAttribute("subject") != null;
+ }
+
+ boolean isSecuredPath(String path) {
+ return !Arrays.stream(unsecuredPaths).anyMatch(path::startsWith);
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ public void setRedirector(Redirector redirector) {
+ this.redirector = redirector;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LoginServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LoginServlet.java"
new file mode 100755
index 0000000..9974ddf
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LoginServlet.java"
@@ -0,0 +1,176 @@
+package io.hawt.web.auth;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import io.hawt.system.AuthHelpers;
+import io.hawt.system.AuthenticateResult;
+import io.hawt.system.Authenticator;
+import io.hawt.system.ConfigManager;
+import io.hawt.web.ServletHelpers;
+import org.jolokia.converter.Converters;
+import org.jolokia.converter.json.JsonConvertOptions;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Login servlet
+ */
+public class LoginServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 187076436862364207L;
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(LoginServlet.class);
+ private static final int DEFAULT_SESSION_TIMEOUT = 1800; // 30 mins
+
+ private Integer timeout = DEFAULT_SESSION_TIMEOUT;
+ private AuthenticationConfiguration authConfiguration;
+
+ private Converters converters = new Converters();
+ private JsonConvertOptions options = JsonConvertOptions.DEFAULT;
+
+ private Redirector redirector = new Redirector();
+
+ @Override
+ public void init() {
+ authConfiguration = AuthenticationConfiguration.getConfiguration(getServletContext());
+ setupSessionTimeout();
+ LOG.info("hawtio login is using {} HttpSession timeout", timeout != null ? timeout + " sec." : "default");
+ }
+
+ private void setupSessionTimeout() {
+ ConfigManager configManager = (ConfigManager) getServletContext().getAttribute(ConfigManager.CONFIG_MANAGER);
+ if (configManager == null) {
+ return;
+ }
+ String timeoutStr = configManager.get("sessionTimeout", Integer.toString(DEFAULT_SESSION_TIMEOUT));
+ if (timeoutStr == null) {
+ return;
+ }
+ try {
+ timeout = Integer.valueOf(timeoutStr);
+ // timeout of 0 means default timeout
+ if (timeout == 0) {
+ timeout = DEFAULT_SESSION_TIMEOUT;
+ }
+ } catch (Exception e) {
+ // ignore and use our own default of 1/2 hour
+ timeout = DEFAULT_SESSION_TIMEOUT;
+ }
+ }
+
+ /**
+ * GET simply returns login.html
+ */
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ if (authConfiguration.isKeycloakEnabled()) {
+ redirector.doRedirect(request, response, "/");
+ } else {
+ redirector.doForward(request, response, "/login.html");
+ }
+ }
+
+ /**
+ * POST with username/password tries authentication and returns result as JSON
+ */
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
+ clearSession(request);
+
+ JSONObject json = ServletHelpers.readObject(request.getReader());
+ String username = (String) json.get("username");
+ String password = (String) json.get("password");
+
+ AuthenticateResult result = Authenticator.authenticate(
+ authConfiguration, request, username, password,
+ subject -> {
+ LOG.info("Logging in user: {}", AuthHelpers.getUsername(subject));
+ setupSession(request, subject, username);
+ sendResponse(response, subject);
+ });
+
+ switch (result) {
+ case AUTHORIZED:
+ // response was sent using the authenticated subject, nothing more to do
+ break;
+ case NOT_AUTHORIZED:
+ case NO_CREDENTIALS:
+ ServletHelpers.doForbidden(response);
+ break;
+ }
+ }
+
+ private void clearSession(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+ if (session == null) {
+ return;
+ }
+ Subject subject = (Subject) session.getAttribute("subject");
+ if (subject != null) {
+ LOG.info("Logging out existing user: {}", AuthHelpers.getUsername(subject));
+ Authenticator.logout(authConfiguration, subject);
+ session.invalidate();
+ }
+ }
+
+ private void setupSession(HttpServletRequest request, Subject subject, String username) {
+ HttpSession session = request.getSession(true);
+ session.setAttribute("subject", subject);
+ session.setAttribute("user", username);
+ session.setAttribute("org.osgi.service.http.authentication.remote.user", username);
+ session.setAttribute("org.osgi.service.http.authentication.type", HttpServletRequest.BASIC_AUTH);
+ session.setAttribute("loginTime", GregorianCalendar.getInstance().getTimeInMillis());
+ if (timeout != null) {
+ session.setMaxInactiveInterval(timeout);
+ }
+ LOG.debug("Http session timeout for user {} is {} sec.", username, session.getMaxInactiveInterval());
+ }
+
+ private void sendResponse(HttpServletResponse response, Subject subject) {
+ response.setContentType("application/json");
+ try (PrintWriter out = response.getWriter()) {
+ Map answer = new HashMap<>();
+
+ List principals = new ArrayList<>();
+ for (Principal principal : subject.getPrincipals()) {
+ Map data = new HashMap<>();
+ data.put("type", principal.getClass().getName());
+ data.put("name", principal.getName());
+ principals.add(data);
+ }
+
+ List credentials = new ArrayList<>();
+ for (Object credential : subject.getPublicCredentials()) {
+ Map data = new HashMap<>();
+ data.put("type", credential.getClass().getName());
+ data.put("credential", credential);
+ credentials.add(data);
+ }
+
+ answer.put("principals", principals);
+ answer.put("credentials", credentials);
+
+ ServletHelpers.writeObject(converters, options, out, answer);
+ } catch (IOException e) {
+ LOG.error("Failed to send response", e);
+ }
+ }
+
+ public void setRedirector(Redirector redirector) {
+ this.redirector = redirector;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LogoutServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LogoutServlet.java"
new file mode 100755
index 0000000..840deaa
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/LogoutServlet.java"
@@ -0,0 +1,52 @@
+package io.hawt.web.auth;
+
+import java.io.IOException;
+import javax.security.auth.Subject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import io.hawt.system.Authenticator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Logout servlet
+ */
+public class LogoutServlet extends HttpServlet {
+
+ private static final long serialVersionUID = -3504832582691232812L;
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(LogoutServlet.class);
+
+ private AuthenticationConfiguration authConfiguration;
+
+ private Redirector redirector = new Redirector();
+
+ @Override
+ public void init() {
+ authConfiguration = AuthenticationConfiguration.getConfiguration(getServletContext());
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ LOG.debug("Logging out user: {}", session.getAttribute("user"));
+ Subject subject = (Subject) session.getAttribute("subject");
+ if (subject != null) {
+ Authenticator.logout(authConfiguration, subject);
+ }
+ session.invalidate();
+ }
+ request.logout();
+
+ redirector.doRedirect(request, response, AuthenticationConfiguration.LOGIN_URL);
+ }
+
+ public void setRedirector(Redirector redirector) {
+ this.redirector = redirector;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/Redirector.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/Redirector.java"
new file mode 100755
index 0000000..5449fcd
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/Redirector.java"
@@ -0,0 +1,36 @@
+package io.hawt.web.auth;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Helper class to perform redirects and forwards which can also be made aware of the Hawtio context path configured for Spring Boot
+ */
+public class Redirector {
+
+ private String applicationContextPath = "";
+
+ public void doRedirect(HttpServletRequest request, HttpServletResponse response, String path) throws IOException {
+ String redirectUrl = "";
+
+ String scheme = request.getServletContext().getInitParameter("scheme");
+ if (scheme != null) {
+ redirectUrl = scheme + "://" + request.getServerName() + ":" + request.getServerPort();
+ }
+
+ redirectUrl += request.getContextPath() + applicationContextPath + path;
+
+ response.sendRedirect(redirectUrl);
+ }
+
+ public void doForward(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException, IOException {
+ request.getRequestDispatcher(applicationContextPath + path).forward(request, response);
+ }
+
+ public void setApplicationContextPath(String applicationContextPath) {
+ this.applicationContextPath = applicationContextPath;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/RelativeRequestUri.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/RelativeRequestUri.java"
new file mode 100755
index 0000000..d164883
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/RelativeRequestUri.java"
@@ -0,0 +1,148 @@
+package io.hawt.web.auth;
+
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+
+import io.hawt.util.Strings;
+
+/**
+ * URI path relative to a given index. An index represents the number of path
+ * components (portions of request uri separated by '/' character) preceding the
+ * start of the uri. For example:
+ *
+ *
+ *
+ * Request URI
+ * Path Index
+ * Relative URI
+ *
+ *
+ * /a/b/c
+ * 0
+ * /a/b/c
+ *
+ *
+ * /a/b/c
+ * 1
+ * /b/c
+ *
+ *
+ * /a/b/c
+ * 3
+ * {@code (empty)}
+ *
+ *
+ */
+public class RelativeRequestUri {
+
+ private static final Pattern PATH_SPLITTER = Pattern.compile("/");
+
+ private final HttpServletRequest request;
+ private final String uriPrefix;
+ private final String uri;
+ private final String[] uriComponents;
+
+ /**
+ * Constructor.
+ *
+ * @param request
+ * HTTP request
+ * @param pathIndex
+ * index of the first path component relative to a servlet root (not
+ * context root!). Path components are parts of the request uri
+ * separated by '/' with the first component (servlet root) being
+ * assigned index zero.
+ * @throws IllegalArgumentException
+ * if pathIndex is negative
+ */
+ public RelativeRequestUri(final HttpServletRequest request,
+ final int pathIndex) {
+ if (pathIndex < 0) {
+ throw new IllegalArgumentException("pathIndex is negative");
+ }
+
+ final String requestUri = Strings.webContextPath(request.getRequestURI());
+ int start = request.getContextPath().length();
+ if (start < requestUri.length() && requestUri.charAt(start) == '/') {
+ start++;
+ }
+
+ if (pathIndex != 0) {
+ int c = 0;
+ do {
+ int i = requestUri.indexOf('/', start);
+ start = i + 1;
+ if (start == 0) {
+ start = requestUri.length();
+ break;
+ }
+ c++;
+ } while (c < pathIndex);
+ }
+
+ if (start < requestUri.length()) {
+ this.uriPrefix = requestUri.substring(0, start);
+ this.uri = requestUri.substring(start);
+ } else {
+ this.uriPrefix = requestUri;
+ this.uri = "";
+ }
+
+ this.uriComponents = uri.isEmpty() ? new String[0]
+ : PATH_SPLITTER.split(uri);
+ this.request = request;
+ }
+
+ /**
+ * Gets the original HTTP request.
+ *
+ * @return HTTP request
+ */
+ public HttpServletRequest getRequest() {
+ return request;
+ }
+
+ /**
+ * Gets the absolute path from the context root to the start of the uri.
+ *
+ * @return uri prefix
+ */
+ public String getPrefix() {
+ return uriPrefix;
+ }
+
+ /**
+ * Gets the uri.
+ *
+ * @return request uri
+ */
+ public String getUri() {
+ return uri;
+ }
+
+ /**
+ * Gets components of the uri. The result is achieved by splitting request uri
+ * using '/' as separator.
+ *
+ * @return array of strings
+ */
+ public String[] getComponents() {
+ return uriComponents;
+ }
+
+ /**
+ * Gets the last component of request uri.
+ *
+ * @return last uri component or null if request is empty
+ */
+ public String getLastComponent() {
+ return uriComponents.length == 0 ? null
+ : uriComponents[uriComponents.length - 1];
+ }
+
+ @Override
+ public String toString() {
+ return getUri();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/SessionExpiryFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/SessionExpiryFilter.java"
new file mode 100755
index 0000000..a3d3b79
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/SessionExpiryFilter.java"
@@ -0,0 +1,171 @@
+package io.hawt.web.auth;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import io.hawt.system.HawtioProperty;
+import io.hawt.util.Strings;
+import io.hawt.web.ServletHelpers;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * If the user has a session, this will ensure it will expire if the user hasn't clicked on any links
+ * within the session expiry period
+ */
+public class SessionExpiryFilter implements Filter {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(SessionExpiryFilter.class);
+
+ public static final String ATTRIBUTE_LAST_ACCESS = "LastAccess";
+
+ private static final List IGNORED_PATHS = Collections.unmodifiableList(Arrays.asList("jolokia", "proxy"));
+
+ private ServletContext context;
+ private AuthenticationConfiguration authConfiguration;
+ private int pathIndex;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ context = filterConfig.getServletContext();
+ authConfiguration = AuthenticationConfiguration.getConfiguration(context);
+
+ String servletPath = (String) filterConfig.getServletContext().getAttribute(HawtioProperty.SERVLET_PATH);
+ if (servletPath == null) {
+ this.pathIndex = 0; // assume hawtio is served from root
+ } else {
+ this.pathIndex = Strings.webContextPath(servletPath).replaceAll("[^/]+", "").length();
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ if (servletRequest instanceof HttpServletRequest
+ && servletResponse instanceof HttpServletResponse) {
+ process((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, filterChain);
+ } else {
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+ }
+
+ private void writeOk(HttpServletResponse response) throws IOException, ServletException {
+ response.setContentType("text/html;charset=UTF-8");
+ try (OutputStream out = response.getOutputStream()) {
+ out.write("ok".getBytes());
+ out.flush();
+ }
+ }
+
+ private void updateLastAccess(HttpSession session, long now) {
+ session.setAttribute(ATTRIBUTE_LAST_ACCESS, now);
+ LOG.debug("Reset LastAccess to: {}", now);
+ }
+
+ private void process(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+ if (context.getAttribute(AuthenticationConfiguration.AUTHENTICATION_ENABLED) == null) {
+ // most likely the authentication filter hasn't been started up yet, let this request through and it can be dealt with by the authentication filter
+ chain.doFilter(request, response);
+ return;
+ }
+
+ HttpSession session = request.getSession(false);
+ boolean enabled = (boolean) context.getAttribute(AuthenticationConfiguration.AUTHENTICATION_ENABLED);
+ final RelativeRequestUri uri = new RelativeRequestUri(request, pathIndex);
+ LOG.debug("Accessing [{}], hawtio path is [{}]", request.getRequestURI(), uri.getUri());
+
+ // pass along if it's the top-level context
+ if (uri.getComponents().length == 0) {
+ if (session != null) {
+ long now = System.currentTimeMillis();
+ updateLastAccess(session, now);
+ }
+ chain.doFilter(request, response);
+ return;
+ }
+
+ String subContext = uri.getComponents()[0];
+ if (session == null || session.getMaxInactiveInterval() < 0) {
+ if (subContext.equals("refresh") && !enabled) {
+ LOG.debug("Authentication disabled, received refresh response, responding with ok");
+ writeOk(response);
+ } else {
+ chain.doFilter(request, response);
+ /*
+ if (!enabled) {
+ LOG.debug("Authentication disabled, allowing request");
+ chain.doFilter(request, response);
+ } else if (request.getHeader(Authenticator.HEADER_AUTHORIZATION) != null) {
+ // there's no session, but we have request with authentication attempt
+ // let's pass it further the filter chain - if authentication will fail, user will get 403 anyway
+ chain.doFilter(request, response);
+ } else {
+ if (noCredentials401 && subContext.equals("jolokia")) {
+ LOG.debug("Authentication enabled, noCredentials401 is true, allowing request for {}",
+ subContext);
+ chain.doFilter(request, response);
+ } else if (subContext.equals("jolokia") ||
+ subContext.equals("proxy") ||
+ subContext.equals("user") ||
+ subContext.equals("exportContext") ||
+ subContext.equals("contextFormatter") ||
+ subContext.equals("upload")) {
+ LOG.debug("Authentication enabled, denying request for {}", subContext);
+ ServletHelpers.doForbidden(response);
+ } else {
+ LOG.debug("Authentication enabled, but allowing request for {}", subContext);
+ chain.doFilter(request, response);
+ }
+ }
+ */
+ }
+ return;
+ }
+
+ int maxInactiveInterval = session.getMaxInactiveInterval();
+ long now = System.currentTimeMillis();
+ if (session.getAttribute(ATTRIBUTE_LAST_ACCESS) != null) {
+ long lastAccess = (long) session.getAttribute(ATTRIBUTE_LAST_ACCESS);
+ long remainder = (now - lastAccess) / 1000;
+ LOG.debug("Session expiry: {}s, duration since last access: {}s", maxInactiveInterval, remainder);
+ if (remainder > maxInactiveInterval) {
+ LOG.info("Expiring session due to inactivity");
+ session.invalidate();
+ ServletHelpers.doForbidden(response);
+ return;
+ }
+ }
+
+ if (subContext.equals("refresh")) {
+ updateLastAccess(session, now);
+ writeOk(response);
+ return;
+ }
+
+ LOG.debug("SubContext: {}", subContext);
+ if (IGNORED_PATHS.contains(subContext) && session.getAttribute(ATTRIBUTE_LAST_ACCESS) != null) {
+ LOG.debug("Not updating LastAccess");
+ } else {
+ updateLastAccess(session, now);
+ }
+
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+ // noop
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/UserServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/UserServlet.java"
new file mode 100755
index 0000000..41529b6
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/UserServlet.java"
@@ -0,0 +1,72 @@
+package io.hawt.web.auth;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import io.hawt.system.ConfigManager;
+import io.hawt.web.ServletHelpers;
+
+/**
+ * Returns the username associated with the current session, if any
+ */
+public class UserServlet extends HttpServlet {
+
+ private static final long serialVersionUID = -1239510748236245667L;
+ private static final String DEFAULT_USER = "public";
+
+ protected ConfigManager config;
+ private boolean authenticationEnabled = true;
+
+ @Override
+ public void init() throws ServletException {
+ config = (ConfigManager) getServletConfig().getServletContext().getAttribute(ConfigManager.CONFIG_MANAGER);
+ if (config != null) {
+ this.authenticationEnabled = config.getBoolean(AuthenticationConfiguration.AUTHENTICATION_ENABLED, true);
+ }
+
+ // JVM system properties can override always
+ if (System.getProperty(AuthenticationConfiguration.HAWTIO_AUTHENTICATION_ENABLED) != null) {
+ this.authenticationEnabled = Boolean.getBoolean(AuthenticationConfiguration.HAWTIO_AUTHENTICATION_ENABLED);
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+
+ if (!authenticationEnabled) {
+ sendResponse(response, DEFAULT_USER);
+ return;
+ }
+
+ String username = getUsername(request, response);
+ if (username == null) {
+ ServletHelpers.doForbidden(response);
+ return;
+ }
+ sendResponse(response, username);
+ }
+
+ private void sendResponse(HttpServletResponse response, String username) throws IOException {
+ response.setContentType("application/json");
+ PrintWriter out = response.getWriter();
+ out.write("\"" + username + "\"");
+ out.flush();
+ out.close();
+ }
+
+ protected String getUsername(HttpServletRequest request, HttpServletResponse response) {
+ HttpSession session = request.getSession(false);
+
+ if (session != null) {
+ return (String) session.getAttribute("user");
+ } else {
+ return null;
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/keycloak/KeycloakServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/keycloak/KeycloakServlet.java"
new file mode 100755
index 0000000..8bf911c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/keycloak/KeycloakServlet.java"
@@ -0,0 +1,182 @@
+package io.hawt.web.auth.keycloak;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.URL;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import io.hawt.system.ConfigManager;
+import io.hawt.util.IOHelper;
+import io.hawt.web.auth.AuthenticationConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Servlet, which aims to return:
+ * - whether keycloak is enabled (true/false) if path '/enabled' is used
+ * - keycloak.json to be used by keycloak JS adapter on frontend if path '/client-config' is used
+ * - validate if current JAAS logged subject is same like SSO user logged through keycloak if path '/validate-subject-matches' is used
+ */
+public class KeycloakServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 3464713772839013741L;
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(KeycloakServlet.class);
+
+ public static final String KEYCLOAK_CLIENT_CONFIG = "keycloakClientConfig";
+
+ public static final String HAWTIO_KEYCLOAK_CLIENT_CONFIG = "hawtio." + KEYCLOAK_CLIENT_CONFIG;
+
+ private String keycloakConfig = null;
+ private AuthenticationConfiguration authConfiguration;
+ private boolean keycloakEnabled;
+
+ @Override
+ public void init() throws ServletException {
+ ConfigManager config = (ConfigManager) getServletContext().getAttribute(ConfigManager.CONFIG_MANAGER);
+
+ authConfiguration = AuthenticationConfiguration.getConfiguration(getServletContext());
+ keycloakEnabled = authConfiguration.isKeycloakEnabled();
+ LOG.info("Keycloak integration is {}", this.keycloakEnabled ? "enabled" : "disabled");
+ if (!keycloakEnabled) {
+ return;
+ }
+
+ String keycloakConfigFile = config.get(KEYCLOAK_CLIENT_CONFIG, null);
+
+ // JVM system properties can override always
+ if (System.getProperty(HAWTIO_KEYCLOAK_CLIENT_CONFIG) != null) {
+ keycloakConfigFile = System.getProperty(HAWTIO_KEYCLOAK_CLIENT_CONFIG);
+ }
+
+ if (keycloakConfigFile == null || keycloakConfigFile.length() == 0) {
+ keycloakConfigFile = defaultKeycloakConfigLocation();
+ }
+
+ LOG.info("Will load keycloak config from location: {}", keycloakConfigFile);
+
+ InputStream is = loadFile(keycloakConfigFile);
+ if (is == null) {
+ LOG.warn("Keycloak client configuration not found!");
+ } else {
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String keycloakConfig = IOHelper.readFully(reader);
+
+ // Minify for perf purposes
+ this.keycloakConfig = keycloakConfig.replaceAll(" ", "").replaceAll(System.lineSeparator(), "");
+ } catch (IOException ioe) {
+ LOG.warn("Couldn't read keycloak configuration file", ioe);
+ } finally {
+ IOHelper.close(is, "keycloakInputStream", LOG);
+ }
+ }
+ }
+
+ /**
+ * Will try to guess the config location based on the server where hawtio is running. Used just if keycloakClientConfig is not provided
+ *
+ * @return config to be used by default
+ */
+ protected String defaultKeycloakConfigLocation() {
+ String karafBase = System.getProperty("karaf.base");
+ if (karafBase != null) {
+ return karafBase + "/etc/keycloak.json";
+ }
+
+ String jettyHome = System.getProperty("jetty.home");
+ if (jettyHome != null) {
+ return jettyHome + "/etc/keycloak.json";
+ }
+
+ String tomcatHome = System.getProperty("catalina.home");
+ if (tomcatHome != null) {
+ return tomcatHome + "/conf/keycloak.json";
+ }
+
+ String jbossHome = System.getProperty("jboss.server.config.dir");
+ if (jbossHome != null) {
+ return jbossHome + "/keycloak.json";
+ }
+
+ // Fallback to classpath inside hawtio.war
+ return "classpath:keycloak.json";
+ }
+
+ protected InputStream loadFile(String keycloakConfigFile) {
+ if (keycloakConfigFile.startsWith("classpath:")) {
+ String classPathLocation = keycloakConfigFile.substring(10);
+ return getClass().getClassLoader().getResourceAsStream(classPathLocation);
+ } else {
+ try {
+ if (!keycloakConfigFile.contains(":")) {
+ //assume file protocol
+ keycloakConfigFile = "file://" + keycloakConfigFile;
+ }
+ return new URL(keycloakConfigFile).openStream();
+ } catch (Exception e) {
+ LOG.warn("Couldn't find keycloak config file on location: " + keycloakConfigFile);
+ LOG.debug("Couldn't find keycloak config file", e);
+ return null;
+ }
+ }
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ String pathInfo = request.getPathInfo();
+ switch (pathInfo) {
+ case "/enabled":
+ renderJSONResponse(response, String.valueOf(keycloakEnabled));
+ break;
+ case "/client-config":
+ if (keycloakConfig == null) {
+ response.sendError(404, "Keycloak client configuration not found");
+ } else {
+ renderJSONResponse(response, keycloakConfig);
+ }
+ break;
+ case "/validate-subject-matches":
+ String keycloakUser = request.getParameter("keycloakUser");
+ if (keycloakUser == null || keycloakUser.length() == 0) {
+ LOG.warn("Parameter 'keycloakUser' not found");
+ }
+ boolean valid = validateKeycloakUser(request, keycloakUser);
+ renderJSONResponse(response, String.valueOf(valid));
+ break;
+ }
+ }
+
+ protected boolean validateKeycloakUser(HttpServletRequest request, String keycloakUser) {
+ HttpSession session = request.getSession(false);
+
+ // No session available. No existing subject logged
+ if (session == null) {
+ return true;
+ }
+
+ String username = (String) session.getAttribute("user");
+ if (username != null && !username.equals(keycloakUser)) {
+ LOG.debug("No matching username found. JAAS username: {}, keycloakUsername: {}. Invalidating session", username, keycloakUser);
+ session.invalidate();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ private void renderJSONResponse(HttpServletResponse response, String text) throws ServletException, IOException {
+ response.setContentType("application/json");
+ PrintWriter writer = response.getWriter();
+ writer.println(text);
+ writer.flush();
+ writer.close();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/keycloak/KeycloakUserServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/keycloak/KeycloakUserServlet.java"
new file mode 100755
index 0000000..27ec4a6
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/auth/keycloak/KeycloakUserServlet.java"
@@ -0,0 +1,54 @@
+package io.hawt.web.auth.keycloak;
+
+import java.util.concurrent.atomic.AtomicReference;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import io.hawt.system.AuthHelpers;
+import io.hawt.system.Authenticator;
+import io.hawt.web.auth.AuthenticationConfiguration;
+import io.hawt.web.auth.UserServlet;
+
+public class KeycloakUserServlet extends UserServlet {
+
+ private static final long serialVersionUID = 1734127369954899957L;
+
+ private AuthenticationConfiguration authConfiguration;
+ private boolean keycloakEnabled;
+
+ @Override
+ public void init() throws ServletException {
+ super.init();
+ authConfiguration = AuthenticationConfiguration.getConfiguration(getServletContext());
+ keycloakEnabled = authConfiguration.isKeycloakEnabled();
+ }
+
+ @Override
+ protected String getUsername(HttpServletRequest req, HttpServletResponse resp) {
+ if (keycloakEnabled) {
+ return getKeycloakUsername(req, resp);
+ } else {
+ return super.getUsername(req, resp);
+ }
+ }
+
+ /**
+ * With Keycloak integration, the Authorization header is available in the request to the UserServlet.
+ */
+ protected String getKeycloakUsername(final HttpServletRequest req, HttpServletResponse resp) {
+ AtomicReference username = new AtomicReference<>();
+ Authenticator.authenticate(
+ authConfiguration, req,
+ subject -> {
+ username.set(AuthHelpers.getUsername(subject));
+
+ // Start httpSession
+ req.getSession(true);
+ }
+ );
+ return username.get();
+ }
+
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/BaseTagHrefFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/BaseTagHrefFilter.java"
new file mode 100755
index 0000000..35461f0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/BaseTagHrefFilter.java"
@@ -0,0 +1,137 @@
+package io.hawt.web.filters;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+public class BaseTagHrefFilter implements Filter {
+
+ public static final String PARAM_APPLICATION_CONTEXT_PATH = "applicationContextPath";
+ private static final String DEFAULT_CONTEXT_PATH = "/hawtio";
+ private String applicationContextPath;
+ private String basePath;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ final String path = filterConfig.getInitParameter(PARAM_APPLICATION_CONTEXT_PATH);
+ applicationContextPath = path != null ? path : "";
+
+ final ServletContext context = filterConfig.getServletContext();
+ final String contextPath = context.getContextPath();
+ if (contextPath == null || contextPath.isEmpty()) {
+ if (!applicationContextPath.startsWith("/")) {
+ basePath = "/";
+ } else {
+ basePath = "";
+ }
+ } else {
+ basePath = contextPath;
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+ // For Spring Boot we need to append the context path of the hawtio application
+ String baseTagHref = basePath + applicationContextPath;
+
+ if (baseTagHref.equals(DEFAULT_CONTEXT_PATH)) {
+ filterChain.doFilter(request, response);
+ } else {
+ final BaseTagHrefRequestWrapper requestWrapper = new BaseTagHrefRequestWrapper((HttpServletResponse) response);
+ filterChain.doFilter(request, requestWrapper);
+
+ final ServletOutputStream out = response.getOutputStream();
+ final String contentType = response.getContentType();
+ final byte[] data = requestWrapper.getData();
+
+ if (contentType != null && contentType.startsWith("text/html")) {
+ if (!baseTagHref.endsWith("/")) {
+ baseTagHref += "/";
+ }
+
+ final String characterEncoding = requestWrapper.getCharacterEncoding() != null ? requestWrapper.getCharacterEncoding() : StandardCharsets.UTF_8.name();
+ final String originalContent = new String(data, characterEncoding);
+ final byte[] replacedContent = originalContent.replaceAll(" ", " ").getBytes(characterEncoding);
+
+ requestWrapper.setContentLength(replacedContent.length);
+ out.write(replacedContent);
+ } else {
+ out.write(data);
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ private class FilterServletOutputStream extends ServletOutputStream {
+
+ private DataOutputStream stream;
+
+ public FilterServletOutputStream(OutputStream output) {
+ stream = new DataOutputStream(output);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ stream.write(b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ stream.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ stream.write(b,off,len);
+ }
+
+ @Override
+ public boolean isReady() {
+ return false;
+ }
+
+ @Override
+ public void setWriteListener(WriteListener writeListener) {
+ }
+ }
+
+
+ private class BaseTagHrefRequestWrapper extends HttpServletResponseWrapper {
+ private ByteArrayOutputStream output;
+
+ public BaseTagHrefRequestWrapper(HttpServletResponse response) {
+ super(response);
+ output = new ByteArrayOutputStream();
+ }
+
+ public byte[] getData() {
+ return output.toByteArray();
+ }
+
+ public ServletOutputStream getOutputStream() {
+ return new FilterServletOutputStream(output);
+ }
+
+ public PrintWriter getWriter() {
+ return new PrintWriter(getOutputStream(), true);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/CORSFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/CORSFilter.java"
new file mode 100755
index 0000000..b5f8120
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/CORSFilter.java"
@@ -0,0 +1,29 @@
+package io.hawt.web.filters;
+
+import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class CORSFilter extends HttpHeaderFilter {
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ if (!allowAny()) {
+ return;
+ }
+ if ("OPTIONS".equals(request.getMethod())) {
+ response.addHeader("Access-Control-Request-Method", "GET, POST, PUT, DELETE");
+ String headers = request.getHeader("Access-Control-Request-Headers");
+ if (headers != null) {
+ response.addHeader("Access-Control-Allow-Headers", headers);
+ }
+ response.addHeader("Access-Control-Max-Age", "" + TimeUnit.DAYS.toSeconds(1));
+ }
+ response.addHeader("Access-Control-Allow-Origin", "*");
+ }
+
+ protected boolean allowAny() {
+ // TODO allow configuration...
+ return true;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/CacheHeadersFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/CacheHeadersFilter.java"
new file mode 100755
index 0000000..4fd5e6d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/CacheHeadersFilter.java"
@@ -0,0 +1,89 @@
+package io.hawt.web.filters;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class CacheHeadersFilter extends HttpHeaderFilter {
+
+ static String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
+ static String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
+ static String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
+
+ private ServletContext servletContext;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+ servletContext = filterConfig.getServletContext();
+ }
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ if (!cacheInBrowser(request)) {
+ response.setHeader("Cache-Control", "max-age=0, no-cache, must-revalidate, proxy-revalidate, private");
+ response.setHeader("Pragma", "no-cache");
+ }
+ }
+
+ public boolean cacheInBrowser(HttpServletRequest request) throws MalformedURLException {
+
+ String servletPath = null;
+ String pathInfo = null;
+
+ if (request.getAttribute(INCLUDE_REQUEST_URI) != null) {
+ servletPath = (String) request.getAttribute(INCLUDE_SERVLET_PATH);
+ pathInfo = (String) request.getAttribute(INCLUDE_PATH_INFO);
+ }
+ if (servletPath == null) {
+ servletPath = request.getServletPath();
+ pathInfo = request.getPathInfo();
+ }
+
+ String resourcePath = joinPaths(servletPath, pathInfo);
+
+ // Don't cache the index.html file.
+ if (resourcePath.equals("/") || resourcePath.endsWith("/index.html")) {
+ return false;
+ }
+
+ // Cache the other static resources.
+ return servletContext.getResource(resourcePath) != null;
+ }
+
+ private String joinPaths(String p1, String p2) {
+ if (p1 == null) {
+ p1 = "";
+ }
+ if (p2 == null) {
+ p2 = "";
+ }
+ if (p1.isEmpty())
+ return p2;
+ if (p2.isEmpty())
+ return p1;
+ return trimSuffix(p1, "/") + "/" + trimPrefix(p2, "/");
+ }
+
+ static String trimPrefix(String value, String prefix) {
+ if (value != null && value.startsWith(prefix)) {
+ return value.substring(prefix.length());
+ } else {
+ return value;
+ }
+ }
+
+ static String trimSuffix(String value, String suffix) {
+ if (value != null && value.endsWith(suffix)) {
+ return value.substring(0, value.length() - suffix.length());
+ } else {
+ return value;
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/ContentSecurityPolicyFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/ContentSecurityPolicyFilter.java"
new file mode 100755
index 0000000..108cc03
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/ContentSecurityPolicyFilter.java"
@@ -0,0 +1,70 @@
+package io.hawt.web.filters;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.URI;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import io.hawt.web.ServletHelpers;
+import io.hawt.web.auth.keycloak.KeycloakServlet;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
+ */
+public class ContentSecurityPolicyFilter extends HttpHeaderFilter {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(ContentSecurityPolicyFilter.class);
+
+ private static String POLICY = "";
+ private static final String POLICY_TEMPLATE =
+ "default-src 'self'; " +
+ "script-src 'self'%s 'unsafe-inline' 'unsafe-eval'; " +
+ "style-src 'self' 'unsafe-inline'; " +
+ "font-src 'self' data:; " +
+ "connect-src 'self'%s; " +
+ "frame-src 'self'%s";
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+
+ String keycloakConfigFile = getConfigParameter(KeycloakServlet.KEYCLOAK_CLIENT_CONFIG);
+ if (keycloakConfigFile == null && System.getProperty(KeycloakServlet.HAWTIO_KEYCLOAK_CLIENT_CONFIG) != null) {
+ keycloakConfigFile = System.getProperty(KeycloakServlet.HAWTIO_KEYCLOAK_CLIENT_CONFIG);
+ }
+
+ boolean addedKeycloakUrl = false;
+ if (keycloakConfigFile != null) {
+ try (FileReader reader = new FileReader(keycloakConfigFile)) {
+ JSONObject json = ServletHelpers.readObject(new BufferedReader(reader));
+ String url = (String) json.get("url");
+ URI uri = URI.create(url);
+ LOG.info("Found Keycloak URL: {}", uri);
+ // mind the initial whitespace
+ String hostPort = " " + uri.getHost();
+ if (uri.getPort() >= 0) {
+ hostPort += ":" + uri.getPort();
+ }
+ POLICY = String.format(POLICY_TEMPLATE, hostPort, hostPort, hostPort);
+ addedKeycloakUrl = true;
+ } catch (IOException e) {
+ LOG.error("Can't read keycloak configuration file", e);
+ }
+ }
+ if (!addedKeycloakUrl) {
+ POLICY = String.format(POLICY_TEMPLATE, "", "", "");
+ }
+ }
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ response.addHeader("Content-Security-Policy", POLICY);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/HttpHeaderFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/HttpHeaderFilter.java"
new file mode 100755
index 0000000..ce02e30
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/HttpHeaderFilter.java"
@@ -0,0 +1,46 @@
+package io.hawt.web.filters;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import io.hawt.system.ConfigManager;
+
+/**
+ * Abstract servlet filter for applying HTTP headers to responses.
+ */
+public abstract class HttpHeaderFilter implements Filter {
+
+ private ConfigManager configManager;
+
+ public HttpHeaderFilter() {
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ configManager = (ConfigManager) filterConfig.getServletContext().getAttribute(ConfigManager.CONFIG_MANAGER);
+ }
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
+ addHeaders((HttpServletRequest) request, (HttpServletResponse) response);
+ }
+ chain.doFilter(request, response);
+ }
+
+ protected abstract void addHeaders(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException;
+
+ protected String getConfigParameter(String key) {
+ return configManager.get(key, null);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/PublicKeyPinningFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/PublicKeyPinningFilter.java"
new file mode 100755
index 0000000..6b79d93
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/PublicKeyPinningFilter.java"
@@ -0,0 +1,39 @@
+package io.hawt.web.filters;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
+ */
+public class PublicKeyPinningFilter extends HttpHeaderFilter {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(PublicKeyPinningFilter.class);
+
+ private static final String PUBLIC_KEY_PINS = "http.publicKeyPins";
+
+ private String headerValue;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+ headerValue = getConfigParameter(PUBLIC_KEY_PINS);
+ if (headerValue != null) {
+ LOG.debug("Public Key Pinning is enabled: {}", headerValue);
+ } else {
+ LOG.debug("Public Key Pinning is disabled");
+ }
+ }
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ if (headerValue != null) {
+ response.addHeader("Public-Key-Pins", headerValue);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/StrictTransportSecurityFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/StrictTransportSecurityFilter.java"
new file mode 100755
index 0000000..1e2d47b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/StrictTransportSecurityFilter.java"
@@ -0,0 +1,39 @@
+package io.hawt.web.filters;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
+ */
+public class StrictTransportSecurityFilter extends HttpHeaderFilter {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(PublicKeyPinningFilter.class);
+
+ private static final String STRICT_TRANSPORT_SECURITY = "http.strictTransportSecurity";
+
+ private String headerValue;
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ super.init(filterConfig);
+ headerValue = getConfigParameter(STRICT_TRANSPORT_SECURITY);
+ if (headerValue != null) {
+ LOG.debug("HTTP Strict Transport Security is enabled: {}", headerValue);
+ } else {
+ LOG.debug("HTTP Strict Transport Security is disabled");
+ }
+ }
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ if (headerValue != null) {
+ response.addHeader("Strict-Transport-Security", headerValue);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XContentTypeOptionsFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XContentTypeOptionsFilter.java"
new file mode 100755
index 0000000..ce70fb3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XContentTypeOptionsFilter.java"
@@ -0,0 +1,15 @@
+package io.hawt.web.filters;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
+ */
+public class XContentTypeOptionsFilter extends HttpHeaderFilter {
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ response.addHeader("X-Content-Type-Options", "nosniff");
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XFrameOptionsFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XFrameOptionsFilter.java"
new file mode 100755
index 0000000..22d0254
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XFrameOptionsFilter.java"
@@ -0,0 +1,15 @@
+package io.hawt.web.filters;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ */
+public class XFrameOptionsFilter extends HttpHeaderFilter {
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ response.addHeader("X-Frame-Options", "SAMEORIGIN");
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XXSSProtectionFilter.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XXSSProtectionFilter.java"
new file mode 100755
index 0000000..7dd132b
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/filters/XXSSProtectionFilter.java"
@@ -0,0 +1,15 @@
+package io.hawt.web.filters;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
+ */
+public class XXSSProtectionFilter extends HttpHeaderFilter {
+
+ @Override
+ protected void addHeaders(HttpServletRequest request, HttpServletResponse response) {
+ response.addHeader("X-XSS-Protection", "1");
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/DefaultProxyAddress.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/DefaultProxyAddress.java"
new file mode 100755
index 0000000..3b138fb
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/DefaultProxyAddress.java"
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.web.kubernetes;
+
+import io.hawt.web.proxy.ProxyAddress;
+
+/**
+ * Default implementation of {@link ProxyAddress}
+ */
+public class DefaultProxyAddress implements ProxyAddress {
+ private final String fullProxyUrl;
+ private final String userName;
+ private final String password;
+
+ public DefaultProxyAddress(String fullProxyUrl, String userName, String password) {
+ this.fullProxyUrl = fullProxyUrl;
+ this.userName = userName;
+ this.password = password;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "DefaultProxyAddress{fullProxyUrl='%s', userName='%s'}",
+ fullProxyUrl, userName);
+ }
+
+ @Override
+ public String getFullProxyUrl() {
+ return fullProxyUrl;
+ }
+
+ @Override
+ public String getUserName() {
+ return userName;
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/OpenShiftProtocolSocketFactory.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/OpenShiftProtocolSocketFactory.java"
new file mode 100755
index 0000000..c4ee6a9
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/OpenShiftProtocolSocketFactory.java"
@@ -0,0 +1,37 @@
+package io.hawt.web.kubernetes;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import org.apache.http.HttpHost;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.protocol.HttpContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A custom implementation which works on PaaS environments like OpenShift
+ */
+public class OpenShiftProtocolSocketFactory extends PlainConnectionSocketFactory {
+ private static final transient Logger LOG = LoggerFactory.getLogger(OpenShiftProtocolSocketFactory.class);
+
+ /**
+ * The factory singleton.
+ */
+ private static final OpenShiftProtocolSocketFactory factory = new OpenShiftProtocolSocketFactory();
+
+ /**
+ * Gets an singleton instance of the OpenShiftProtocolSocketFactory.
+ *
+ * @return a OpenShiftProtocolSocketFactory
+ */
+ public static OpenShiftProtocolSocketFactory getSocketFactory() {
+ return factory;
+ }
+
+ @Override
+ public Socket connectSocket(int i, Socket socket, HttpHost httpHost, InetSocketAddress inetSocketAddress, InetSocketAddress inetSocketAddress1, HttpContext httpContext) throws IOException {
+ return super.connectSocket(i, socket, httpHost, inetSocketAddress, null /* local address */, httpContext);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/PodServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/PodServlet.java"
new file mode 100755
index 0000000..4a00653
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/PodServlet.java"
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.web.kubernetes;
+
+import javax.servlet.http.HttpServletRequest;
+
+import io.hawt.util.Strings;
+import io.hawt.web.proxy.ProxyAddress;
+import io.hawt.web.proxy.ProxyServlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Proxies /pod/name/port/* to the pod IP/port for 'name' using the Kubernetes service lookup and then
+ * passes the rest of the URI to the underlying service.
+ */
+public class PodServlet extends ProxyServlet {
+ private static final transient Logger LOG = LoggerFactory.getLogger(PodServlet.class);
+
+ @Override
+ protected ProxyAddress parseProxyAddress(HttpServletRequest servletRequest) {
+ String reqQueryString = servletRequest.getQueryString();
+ String queryPostfix = "";
+ if (Strings.isNotBlank(reqQueryString)) {
+ queryPostfix = "?" + reqQueryString;
+ }
+
+ String userName = null;
+ String password = null;
+ String podName = servletRequest.getPathInfo();
+ if (podName == null) {
+ podName = "";
+ }
+ if (podName.startsWith("/")) {
+ podName = podName.substring(1);
+ }
+ int idx = podName.indexOf('/');
+ String podPort = "";
+ String podPath = "/";
+ if (idx > 0) {
+ podPath = podName.substring(idx);
+ podName = podName.substring(0, idx);
+
+ idx = podPath.indexOf('/', 1);
+ if (idx >= 0) {
+ podPort = podPath.substring(1, idx);
+ podPath = podPath.substring(idx);
+ }
+ }
+ if (podName.isEmpty()) {
+ // lets list the pods for /pod
+ String url = ServiceResolver.getSingleton().getServiceURL("kubernetes");
+ if (url == null) {
+ return null;
+ }
+ url += "/kubernetes/api/v1beta2/pods" + queryPostfix;
+ return new DefaultProxyAddress(url, userName, password);
+ }
+ String url = ServiceResolver.getSingleton().getPodUrl(podName, podPort);
+ if (url == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No pod for: " + podName + " port: " + podPort + " path: " + podPath);
+ }
+ System.out.println("No pod for: " + podName + " port: " + podPort + " path: " + podPath);
+ return null;
+ } else {
+ url += podPath + queryPostfix;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Invoking: " + url + " from pod: " + podName + " port: " + podPort + " path: " + podPath);
+ }
+ System.out.println("Invoking: " + url + " from pod: " + podName + " port: " + podPort + " path: " + podPath);
+ return new DefaultProxyAddress(url, userName, password);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/ServiceResolver.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/ServiceResolver.java"
new file mode 100755
index 0000000..51db345
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/ServiceResolver.java"
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.web.kubernetes;
+
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Resolves the service / container names to a URL to invoke HTTP / HTTPS requests
+ */
+public class ServiceResolver {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ServiceResolver.class);
+
+ public static ServiceResolver singleton = new ServiceResolver();
+ public static ObjectName OBJECT_NAME;
+
+ static {
+ try {
+ OBJECT_NAME = new ObjectName("io.fabric8:type=KubernetesManager");
+ } catch (MalformedObjectNameException e) {
+ // ignore
+ }
+ }
+
+ public static ServiceResolver getSingleton() {
+ return singleton;
+ }
+
+ public String getServiceURL(String serviceName) {
+ ObjectName objectName = OBJECT_NAME;
+ String operationName = "getServiceUrl";
+ Object[] params = {serviceName};
+ String[] types = {String.class.getName()};
+ Object answer = invokeMBeanOperation(objectName, operationName, params, types);
+ return answer != null ? answer.toString() : null;
+ }
+
+ public String getPodUrl(String podName, String port) {
+ ObjectName objectName = OBJECT_NAME;
+ String operationName = "getPodUrl";
+ Object[] params = {podName, port};
+ String[] types = {String.class.getName(), String.class.getName()};
+ Object answer = invokeMBeanOperation(objectName, operationName, params, types);
+ return answer != null ? answer.toString() : null;
+ }
+
+ protected static Object invokeMBeanOperation(ObjectName objectName, String operationName, Object[] params, String[] types) {
+ MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ Object answer = null;
+ if (mBeanServer != null && mBeanServer.isRegistered(objectName)) {
+ try {
+ answer = mBeanServer.invoke(objectName, operationName, params, types);
+ } catch (Exception e) {
+ LOG.warn("Could not invoke: " + operationName + Arrays.asList(params) + " on " + objectName + ". " + e, e);
+ }
+ }
+ return answer;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/ServiceServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/ServiceServlet.java"
new file mode 100755
index 0000000..7b9337a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/kubernetes/ServiceServlet.java"
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.web.kubernetes;
+
+import javax.servlet.http.HttpServletRequest;
+
+import io.hawt.util.Strings;
+import io.hawt.web.proxy.ProxyAddress;
+import io.hawt.web.proxy.ProxyServlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Proxies /service/name/* to the service host/port for 'name' using the Kubernetes service lookup and then
+ * passes the rest of the URI to the underlying service.
+ */
+public class ServiceServlet extends ProxyServlet {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ServiceServlet.class);
+
+ @Override
+ protected ProxyAddress parseProxyAddress(HttpServletRequest servletRequest) {
+ String reqQueryString = servletRequest.getQueryString();
+ String queryPostfix = "";
+ if (Strings.isNotBlank(reqQueryString)) {
+ queryPostfix = "?" + reqQueryString;
+ }
+ String userName = null;
+ String password = null;
+ String serviceName = servletRequest.getPathInfo();
+ if (serviceName == null) {
+ serviceName = "";
+ }
+ if (serviceName.startsWith("/")) {
+ serviceName = serviceName.substring(1);
+ }
+ int idx = serviceName.indexOf('/');
+ String servicePath = "/";
+ if (idx > 0) {
+ servicePath = serviceName.substring(idx);
+ serviceName = serviceName.substring(0, idx);
+ }
+ if (serviceName.length() == 0) {
+ // lets list the services for /service
+ serviceName = "kubernetes";
+ servicePath = "/kubernetes/api/v1beta2/services";
+ }
+
+ String url = ServiceResolver.getSingleton().getServiceURL(serviceName);
+ if (url == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No service for: " + serviceName + " path: " + servicePath);
+ }
+ return null;
+ } else {
+ url += servicePath + queryPostfix;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Invoking: " + url + " from service: " + serviceName + " path: " + servicePath);
+ }
+ return new DefaultProxyAddress(url, userName, password);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyAddress.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyAddress.java"
new file mode 100755
index 0000000..1833522
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyAddress.java"
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.web.proxy;
+
+/**
+ * Proxy address interface.
+ */
+public interface ProxyAddress {
+
+ String getFullProxyUrl();
+
+ String getUserName();
+
+ String getPassword();
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyDetails.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyDetails.java"
new file mode 100755
index 0000000..fe12565
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyDetails.java"
@@ -0,0 +1,266 @@
+package io.hawt.web.proxy;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+
+import io.hawt.system.AuthInfo;
+import io.hawt.system.Authenticator;
+import io.hawt.util.Strings;
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A helper object to store the proxy location details
+ */
+public class ProxyDetails implements ProxyAddress {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ProxyDetails.class);
+
+ private String stringProxyURL;
+ private String hostAndPort;
+ private String scheme = "http";
+ private String path = "";
+ private String userName;
+ private String password;
+ private String host;
+ private int port = 80;
+
+ public static final String USER_PARAM = "_user";
+ public static final String PWD_PARAM = "_pwd";
+
+ private static Set ignoreHeaderNames = new HashSet(Arrays.asList(USER_PARAM, PWD_PARAM, "_url", "url"));
+
+ public ProxyDetails(HttpServletRequest httpServletRequest) {
+ this(httpServletRequest.getPathInfo());
+
+ String authHeader = httpServletRequest.getHeader(Authenticator.HEADER_AUTHORIZATION);
+
+ if (authHeader != null && !authHeader.equals("")) {
+
+ AuthInfo info = new AuthInfo();
+
+ Authenticator.extractAuthInfo(authHeader, (userName, password) -> {
+ info.username = userName;
+ info.password = password;
+ });
+
+ userName = info.username;
+ password = info.password;
+ }
+
+ // lets add the query parameters
+ Enumeration> iter = httpServletRequest.getParameterNames();
+ while (iter != null && iter.hasMoreElements()) {
+ Object next = iter.nextElement();
+ if (next instanceof String) {
+ String name = next.toString();
+ if (!ignoreHeaderNames.contains(name)) {
+ String[] values = httpServletRequest.getParameterValues(name);
+ for (String value : values) {
+ String prefix = "?";
+ if (stringProxyURL.contains("?")) {
+ prefix = "&";
+ }
+ stringProxyURL += prefix + name + "=" + value;
+ }
+ }
+ }
+ }
+ }
+
+ public ProxyDetails(String pathInfo) {
+ hostAndPort = pathInfo.replace(" ", "%20");
+
+ if (hostAndPort == null) {
+ return;
+ }
+
+ while (hostAndPort.startsWith("/")) {
+ hostAndPort = hostAndPort.substring(1);
+ }
+
+ if (hostAndPort.startsWith("http/")) {
+ scheme = "http";
+ hostAndPort = hostAndPort.substring(5);
+ } else if (hostAndPort.startsWith("https/")) {
+ scheme = "https";
+ hostAndPort = hostAndPort.substring(6);
+ }
+
+ // remove user/pwd
+ int idx = hostAndPort.indexOf("@");
+ if (idx > 0) {
+ userName = hostAndPort.substring(0, idx);
+ hostAndPort = hostAndPort.substring(idx + 1);
+
+ idx = indexOf(userName, ":", "/");
+ if (idx > 0) {
+ password = userName.substring(idx + 1);
+ userName = userName.substring(0, idx);
+ }
+ }
+ host = hostAndPort;
+ int schemeIdx = indexOf(hostAndPort, "://");
+ if (schemeIdx > 0) {
+ scheme = hostAndPort.substring(0, schemeIdx);
+ hostAndPort = hostAndPort.substring(schemeIdx + 3);
+ } else {
+ // hawtio may report scheme without a double slash so lets handle that 'bug' also
+ schemeIdx = indexOf(hostAndPort, ":/");
+ if (schemeIdx > 0) {
+ scheme = hostAndPort.substring(0, schemeIdx);
+ hostAndPort = hostAndPort.substring(schemeIdx + 2);
+ }
+ }
+ idx = indexOf(hostAndPort, ":", "/");
+ if (idx > 0) {
+ host = hostAndPort.substring(0, idx);
+ String portText = hostAndPort.substring(idx + 1);
+ idx = portText.indexOf("/");
+ if (idx >= 0) {
+ path = portText.substring(idx);
+ portText = portText.substring(0, idx);
+ }
+
+ if (Strings.isNotBlank(portText)) {
+ // portText may be a port unless its default
+ try {
+ port = Integer.parseInt(portText);
+ hostAndPort = host + ":" + port;
+ } catch (NumberFormatException e) {
+ port = "http".equals(scheme) ? 80 : 443;
+ // we do not have a port, so path is the portText
+ path = "/" + portText + path;
+ hostAndPort = host;
+ }
+ } else {
+ hostAndPort = host;
+ }
+ }
+
+ stringProxyURL = scheme + "://" + hostAndPort + path;
+
+ // we do not support query parameters
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Proxying to " + stringProxyURL + " as user: " + userName);
+ }
+ }
+
+ public boolean isAllowed(Set whitelist) {
+ if (whitelist.contains("*")) {
+ return true;
+ }
+ // host may contain port number! (e.g. "localhost:9000")
+ return whitelist.contains(host.split(":")[0]);
+ }
+
+ public boolean isAllowed(List regexWhitelist) {
+ // host may contain port number! (e.g. "localhost:9000")
+ String hostWithoutPort = host.split(":")[0];
+
+ for (Pattern pattern : regexWhitelist) {
+ if (pattern.matcher(hostWithoutPort).matches()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getFullProxyUrl() {
+ return stringProxyURL;
+ }
+
+ @Override
+ public String toString() {
+ return "ProxyDetails{" +
+ userName + "@" + hostAndPort + "/" + stringProxyURL
+ + "}";
+ }
+
+ /**
+ * Returns the lowest index of the given list of values
+ */
+ protected int indexOf(String text, String... values) {
+ int answer = -1;
+ for (String value : values) {
+ int idx = text.indexOf(value);
+ if (idx >= 0) {
+ if (answer < 0 || idx < answer) {
+ answer = idx;
+ }
+ }
+ }
+ return answer;
+ }
+
+ public HttpClient createHttpClient(HttpMethod httpMethodProxyRequest) {
+ HttpClient client = new HttpClient();
+
+ if (userName != null) {
+ //client.getParams().setAuthenticationPreemptive(true);
+ httpMethodProxyRequest.setDoAuthentication(true);
+
+ Credentials defaultcreds = new UsernamePasswordCredentials(userName, password);
+ client.getState().setCredentials(new AuthScope(host, port, AuthScope.ANY_REALM), defaultcreds);
+ }
+ return client;
+ }
+
+ public String getStringProxyURL() {
+ return stringProxyURL;
+ }
+
+ public String getProxyHostAndPort() {
+ return hostAndPort;
+ }
+
+ public String getProxyPath() {
+ return path;
+ }
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ @Override
+ public String getUserName() {
+ return userName;
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ public String getHostAndPort() {
+ return hostAndPort;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public boolean isValid() {
+ return hostAndPort != null;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyServlet.java"
new file mode 100755
index 0000000..51eb4cf
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/proxy/ProxyServlet.java"
@@ -0,0 +1,527 @@
+package io.hawt.web.proxy;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.BitSet;
+import java.util.Enumeration;
+import java.util.Formatter;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import io.hawt.system.ConfigManager;
+import io.hawt.system.ProxyWhitelist;
+import io.hawt.util.Strings;
+import io.hawt.web.ForbiddenReason;
+import io.hawt.web.ServletHelpers;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.methods.AbortableHttpRequest;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.utils.URIUtils;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContextBuilder;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.message.HeaderGroup;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An HTTP reverse proxy/gateway servlet. It is designed to be extended for customization
+ * if desired. Most of the work is handled by
+ * Apache HttpClient .
+ *
+ * There are alternatives to a servlet based proxy such as Apache mod_proxy if that is available to you. However
+ * this servlet is easily customizable by Java, secure-able by your web application's security (e.g. spring-security),
+ * portable across servlet engines, and is embeddable into another web application.
+ *
+ *
+ * Inspiration: http://httpd.apache.org/docs/2.0/mod/mod_proxy.html
+ *
+ *
+ * Original implementation at https://github.com/mitre/HTTP-Proxy-Servlet, released under ASL 2.0.
+ *
+ *
+ * @author David Smiley dsmiley@mitre.org
+ */
+public class ProxyServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 7792226114533360114L;
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(ProxyServlet.class);
+
+ /* INIT PARAMETER NAME CONSTANTS */
+
+ /**
+ * A boolean parameter name to enable logging of input and target URLs to the servlet log.
+ *
+ * @deprecated Use SLF4J {@link Logger}
+ */
+ @Deprecated
+ public static final String P_LOG = "log";
+
+ /**
+ * A boolean parameter name to enable forwarding of the client IP
+ */
+ public static final String P_FORWARDEDFOR = "forwardip";
+
+ /**
+ * Whether we accept self-signed SSL certificates
+ */
+ private static final String PROXY_ACCEPT_SELF_SIGNED_CERTS = "hawtio.proxyDisableCertificateValidation";
+ private static final String PROXY_ACCEPT_SELF_SIGNED_CERTS_ENV = "PROXY_DISABLE_CERT_VALIDATION";
+
+ public static final String PROXY_WHITELIST = "proxyWhitelist";
+ public static final String LOCAL_ADDRESS_PROBING = "localAddressProbing";
+
+ public static final String HAWTIO_PROXY_WHITELIST = "hawtio." + PROXY_WHITELIST;
+ public static final String HAWTIO_LOCAL_ADDRESS_PROBING = "hawtio." + LOCAL_ADDRESS_PROBING;
+
+ /* MISC */
+
+ protected boolean doLog = false;
+ protected boolean doForwardIP = true;
+ protected boolean acceptSelfSignedCerts = false;
+
+ protected ProxyWhitelist whitelist;
+
+ protected CloseableHttpClient proxyClient;
+ private CookieStore cookieStore;
+
+ @Override
+ public String getServletInfo() {
+ return "A proxy servlet by David Smiley, dsmiley@mitre.org";
+ }
+
+ @Override
+ public void init(ServletConfig servletConfig) throws ServletException {
+ super.init(servletConfig);
+
+ ConfigManager config = (ConfigManager) getServletContext().getAttribute(ConfigManager.CONFIG_MANAGER);
+
+ String whitelistStr = config.get(PROXY_WHITELIST, servletConfig.getInitParameter(PROXY_WHITELIST));
+ boolean probeLocal = config.getBoolean(LOCAL_ADDRESS_PROBING, true);
+ whitelist = new ProxyWhitelist(whitelistStr, probeLocal);
+
+ String doForwardIPString = servletConfig.getInitParameter(P_FORWARDEDFOR);
+ if (doForwardIPString != null) {
+ this.doForwardIP = Boolean.parseBoolean(doForwardIPString);
+ }
+
+ String doLogStr = servletConfig.getInitParameter(P_LOG);
+ if (doLogStr != null) {
+ this.doLog = Boolean.parseBoolean(doLogStr);
+ }
+
+ cookieStore = new BasicCookieStore();
+ HttpClientBuilder httpClientBuilder = HttpClients.custom()
+ .setDefaultCookieStore(cookieStore)
+ .useSystemProperties();
+
+ if (System.getProperty(PROXY_ACCEPT_SELF_SIGNED_CERTS) != null) {
+ acceptSelfSignedCerts = Boolean.parseBoolean(System.getProperty(PROXY_ACCEPT_SELF_SIGNED_CERTS));
+ } else if (System.getenv(PROXY_ACCEPT_SELF_SIGNED_CERTS_ENV) != null) {
+ acceptSelfSignedCerts = Boolean.parseBoolean(System.getenv(PROXY_ACCEPT_SELF_SIGNED_CERTS_ENV));
+ }
+
+ if (acceptSelfSignedCerts) {
+ try {
+ SSLContextBuilder builder = new SSLContextBuilder();
+ builder.loadTrustMaterial(null, (X509Certificate[] x509Certificates, String s) -> true);
+ SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
+ builder.build(), SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ httpClientBuilder.setSSLSocketFactory(sslsf);
+ } catch (NoSuchAlgorithmException e) {
+ throw new ServletException(e);
+ } catch (KeyStoreException e) {
+ throw new ServletException(e);
+ } catch (KeyManagementException e) {
+ throw new ServletException(e);
+ }
+ }
+
+ proxyClient = httpClientBuilder.build();
+ }
+
+ @Override
+ public void destroy() {
+ try {
+ proxyClient.close();
+ } catch (IOException e) {
+ log("While destroying servlet, shutting down httpclient: " + e, e);
+ LOG.error("While destroying servlet, shutting down httpclient: " + e, e);
+ }
+ super.destroy();
+ }
+
+ @Override
+ protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
+ throws ServletException, IOException {
+ // Make the Request
+ //note: we won't transfer the protocol version because I'm not sure it would truly be compatible
+ ProxyAddress proxyAddress = parseProxyAddress(servletRequest);
+ if (proxyAddress == null || proxyAddress.getFullProxyUrl() == null) {
+ servletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ // TODO Implement whitelist protection for Kubernetes services as well
+ if (proxyAddress instanceof ProxyDetails) {
+ ProxyDetails details = (ProxyDetails) proxyAddress;
+ if (!whitelist.isAllowed(details)) {
+ LOG.debug("Rejecting {}", proxyAddress);
+ ServletHelpers.doForbidden(servletResponse, ForbiddenReason.HOST_NOT_ALLOWED);
+ return;
+ }
+ }
+
+ String method = servletRequest.getMethod();
+ String proxyRequestUri = proxyAddress.getFullProxyUrl();
+
+ URI targetUriObj;
+ try {
+ targetUriObj = new URI(proxyRequestUri);
+ } catch (URISyntaxException e) {
+ LOG.error("URL '{}' is not valid: {}", proxyRequestUri, e.getMessage());
+ servletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+
+ HttpRequest proxyRequest;
+ //spec: RFC 2616, sec 4.3: either of these two headers signal that there is a message body.
+ if (servletRequest.getHeader(HttpHeaders.CONTENT_LENGTH) != null ||
+ servletRequest.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) {
+ HttpEntityEnclosingRequest eProxyRequest = new BasicHttpEntityEnclosingRequest(method, proxyRequestUri);
+ // Add the input entity (streamed)
+ // note: we don't bother ensuring we close the servletInputStream since the container handles it
+ eProxyRequest.setEntity(new InputStreamEntity(servletRequest.getInputStream(), servletRequest.getContentLength()));
+ proxyRequest = eProxyRequest;
+ } else {
+ proxyRequest = new BasicHttpRequest(method, proxyRequestUri);
+ }
+
+ copyRequestHeaders(servletRequest, proxyRequest, targetUriObj);
+
+ String username = proxyAddress.getUserName();
+ String password = proxyAddress.getPassword();
+
+ if (Strings.isNotBlank(username) && Strings.isNotBlank(password)) {
+ String encodedCreds = Base64.encodeBase64String((username + ":" + password).getBytes());
+ proxyRequest.setHeader("Authorization", "Basic " + encodedCreds);
+ }
+
+ Header proxyAuthHeader = proxyRequest.getFirstHeader("Authorization");
+ if (proxyAuthHeader != null) {
+ String proxyAuth = proxyAuthHeader.getValue();
+ // if remote jolokia credentials have changed, we have to clear session cookies in http-client
+ HttpSession session = servletRequest.getSession();
+ if (session != null) {
+ String previousProxyCredentials = (String) session.getAttribute("proxy-credentials");
+ if (previousProxyCredentials != null && !previousProxyCredentials.equals(proxyAuth)) {
+ cookieStore.clear();
+ }
+ session.setAttribute("proxy-credentials", proxyAuth);
+ }
+ }
+
+ setXForwardedForHeader(servletRequest, proxyRequest);
+
+ CloseableHttpResponse proxyResponse = null;
+ int statusCode = 0;
+ try {
+
+ // Execute the request
+ if (doLog) {
+ log("proxy " + method + " uri: " + servletRequest.getRequestURI() + " -- " + proxyRequest.getRequestLine().getUri());
+ }
+ LOG.debug("proxy {} uri: {} -- {}", method, servletRequest.getRequestURI(), proxyRequest.getRequestLine().getUri());
+ proxyResponse = proxyClient.execute(URIUtils.extractHost(targetUriObj), proxyRequest);
+
+ // Process the response
+ statusCode = proxyResponse.getStatusLine().getStatusCode();
+
+ if (statusCode == 401 || statusCode == 403) {
+ if (doLog) {
+ log("Authentication Failed on remote server " + proxyRequestUri);
+ }
+ LOG.debug("Authentication Failed on remote server {}", proxyRequestUri);
+ } else if (doResponseRedirectOrNotModifiedLogic(servletRequest, servletResponse, proxyResponse, statusCode, targetUriObj)) {
+ //the response is already "committed" now without any body to send
+ //TODO copy response headers?
+ return;
+ }
+
+ // Pass the response code. This method with the "reason phrase" is deprecated but it's the only way to pass the
+ // reason along too.
+ //noinspection deprecation
+ servletResponse.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase());
+
+ copyResponseHeaders(proxyResponse, servletResponse);
+
+ // Send the content to the client
+ copyResponseEntity(proxyResponse, servletResponse);
+
+ } catch (Exception e) {
+ //abort request, according to best practice with HttpClient
+ if (proxyRequest instanceof AbortableHttpRequest) {
+ AbortableHttpRequest abortableHttpRequest = (AbortableHttpRequest) proxyRequest;
+ abortableHttpRequest.abort();
+ }
+ // Exception needs to be suppressed for security reason
+ LOG.debug("Proxy to " + proxyRequestUri + " failed", e);
+ if (e instanceof ConnectException || e instanceof UnknownHostException) {
+ // Target host refused connection or doesn't exist
+ servletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ } else if (e instanceof ServletException) {
+ // Redirect / Not Modified failed
+ servletResponse.sendError(HttpServletResponse.SC_BAD_GATEWAY, e.getMessage());
+ } else if (e instanceof SecurityException) {
+ servletResponse.setHeader("WWW-Authenticate", "Basic");
+ servletResponse.sendError(statusCode, e.getMessage());
+ } else {
+ servletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
+ }
+
+ } finally {
+ if (proxyResponse != null) {
+ // Make sure the entire entity was consumed
+ EntityUtils.consumeQuietly(proxyResponse.getEntity());
+
+ try {
+ proxyResponse.close();
+ } catch (IOException e) {
+ LOG.error("Error closing proxy client response: {}", e.getMessage());
+ }
+ }
+ //Note: Don't need to close servlet outputStream:
+ // http://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter
+ }
+ }
+
+ protected ProxyAddress parseProxyAddress(HttpServletRequest servletRequest) {
+ return new ProxyDetails(servletRequest);
+ }
+
+ protected boolean doResponseRedirectOrNotModifiedLogic(
+ HttpServletRequest servletRequest, HttpServletResponse servletResponse,
+ HttpResponse proxyResponse, int statusCode, URI targetUriObj)
+ throws ServletException, IOException {
+ // Check if the proxy response is a redirect
+ // The following code is adapted from org.tigris.noodle.filters.CheckForRedirect
+ if (statusCode >= HttpServletResponse.SC_MULTIPLE_CHOICES /* 300 */
+ && statusCode < HttpServletResponse.SC_NOT_MODIFIED /* 304 */) {
+ Header locationHeader = proxyResponse.getLastHeader(HttpHeaders.LOCATION);
+ if (locationHeader == null) {
+ throw new ServletException("Received status code: " + statusCode
+ + " but no " + HttpHeaders.LOCATION + " header was found in the response");
+ }
+ // Modify the redirect to go to this proxy servlet rather that the proxied host
+ String locStr = rewriteUrlFromResponse(servletRequest, locationHeader.getValue(), targetUriObj.toString());
+
+ servletResponse.sendRedirect(locStr);
+ return true;
+ }
+ // 304 needs special handling. See:
+ // http://www.ics.uci.edu/pub/ietf/http/rfc1945.html#Code304
+ // We get a 304 whenever passed an 'If-Modified-Since'
+ // header and the data on disk has not changed; server
+ // responds w/ a 304 saying I'm not going to send the
+ // body because the file has not changed.
+ if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) {
+ servletResponse.setIntHeader(HttpHeaders.CONTENT_LENGTH, 0);
+ servletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * These are the "hop-by-hop" headers that should not be copied.
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
+ * I use an HttpClient HeaderGroup class instead of Set because this
+ * approach does case insensitive lookup faster.
+ */
+ protected static final HeaderGroup hopByHopHeaders;
+
+ static {
+ hopByHopHeaders = new HeaderGroup();
+ String[] headers = new String[] {
+ "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization",
+ "TE", "Trailers", "Transfer-Encoding", "Upgrade", "Cookie", "Set-Cookie" };
+ for (String header : headers) {
+ hopByHopHeaders.addHeader(new BasicHeader(header, null));
+ }
+ }
+
+ /**
+ * Copy request headers from the servlet client to the proxy request.
+ */
+ protected void copyRequestHeaders(HttpServletRequest servletRequest, HttpRequest proxyRequest, URI targetUriObj) {
+ // Get an Enumeration of all of the header names sent by the client
+ Enumeration enumerationOfHeaderNames = servletRequest.getHeaderNames();
+ while (enumerationOfHeaderNames.hasMoreElements()) {
+ String headerName = (String) enumerationOfHeaderNames.nextElement();
+ //Instead the content-length is effectively set via InputStreamEntity
+ if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH))
+ continue;
+ if (hopByHopHeaders.containsHeader(headerName))
+ continue;
+
+ Enumeration headers = servletRequest.getHeaders(headerName);
+ while (headers.hasMoreElements()) {//sometimes more than one value
+ String headerValue = (String) headers.nextElement();
+ // In case the proxy host is running multiple virtual servers,
+ // rewrite the Host header to ensure that we get content from
+ // the correct virtual server
+ if (headerName.equalsIgnoreCase(HttpHeaders.HOST)) {
+ HttpHost host = URIUtils.extractHost(targetUriObj);
+ if (host != null) {
+ headerValue = host.getHostName();
+ if (headerValue != null && host.getPort() != -1) {
+ headerValue += ":" + host.getPort();
+ }
+ }
+ }
+ proxyRequest.addHeader(headerName, headerValue);
+ }
+ }
+ }
+
+ private void setXForwardedForHeader(HttpServletRequest servletRequest,
+ HttpRequest proxyRequest) {
+ String headerName = "X-Forwarded-For";
+ if (doForwardIP) {
+ String newHeader = servletRequest.getRemoteAddr();
+ String existingHeader = servletRequest.getHeader(headerName);
+ if (existingHeader != null) {
+ newHeader = existingHeader + ", " + newHeader;
+ }
+ proxyRequest.setHeader(headerName, newHeader);
+ }
+ }
+
+ /**
+ * Copy proxied response headers back to the servlet client.
+ */
+ protected void copyResponseHeaders(HttpResponse proxyResponse, HttpServletResponse servletResponse) {
+ for (Header header : proxyResponse.getAllHeaders()) {
+ if (hopByHopHeaders.containsHeader(header.getName()))
+ continue;
+ servletResponse.addHeader(header.getName(), header.getValue());
+ }
+ }
+
+ /**
+ * Copy response body data (the entity) from the proxy to the servlet client.
+ */
+ protected void copyResponseEntity(HttpResponse proxyResponse, HttpServletResponse servletResponse) throws IOException {
+ HttpEntity entity = proxyResponse.getEntity();
+ if (entity != null) {
+ OutputStream servletOutputStream = servletResponse.getOutputStream();
+ entity.writeTo(servletOutputStream);
+ }
+ }
+
+ /**
+ * For a redirect response from the target server, this translates {@code theUrl} to redirect to
+ * and translates it to one the original client can use.
+ */
+ protected String rewriteUrlFromResponse(HttpServletRequest servletRequest, String theUrl, String targetUri) {
+ //TODO document example paths
+ if (theUrl.startsWith(targetUri)) {
+ String curUrl = servletRequest.getRequestURL().toString();//no query
+ String pathInfo = servletRequest.getPathInfo();
+ if (pathInfo != null) {
+ assert curUrl.endsWith(pathInfo);
+ curUrl = curUrl.substring(0, curUrl.length() - pathInfo.length());//take pathInfo off
+ }
+ theUrl = curUrl + theUrl.substring(targetUri.length());
+ }
+ return theUrl;
+ }
+
+ /**
+ * Encodes characters in the query or fragment part of the URI.
+ *
+ * Unfortunately, an incoming URI sometimes has characters disallowed by the spec. HttpClient
+ * insists that the outgoing proxied request has a valid URI because it uses Java's {@link URI}.
+ * To be more forgiving, we must escape the problematic characters. See the URI class for the
+ * spec.
+ *
+ * @param in example: name=value&foo=bar#fragment
+ */
+ protected static CharSequence encodeUriQuery(CharSequence in) {
+ //Note that I can't simply use URI.java to encode because it will escape pre-existing escaped things.
+ StringBuilder outBuf = null;
+ Formatter formatter = null;
+ for (int i = 0; i < in.length(); i++) {
+ char c = in.charAt(i);
+ boolean escape = true;
+ if (c < 128) {
+ if (asciiQueryChars.get((int) c)) {
+ escape = false;
+ }
+ } else if (!Character.isISOControl(c) && !Character.isSpaceChar(c)) {//not-ascii
+ escape = false;
+ }
+ if (!escape) {
+ if (outBuf != null)
+ outBuf.append(c);
+ } else {
+ //escape
+ if (outBuf == null) {
+ outBuf = new StringBuilder(in.length() + 5 * 3);
+ outBuf.append(in, 0, i);
+ formatter = new Formatter(outBuf);
+ }
+ //leading %, 0 padded, width 2, capital hex
+ formatter.format("%%%02X", (int) c);//TODO
+ }
+ }
+ return outBuf != null ? outBuf : in;
+ }
+
+ protected static final BitSet asciiQueryChars;
+
+ static {
+ char[] c_unreserved = "_-!.~'()*".toCharArray();//plus alphanum
+ char[] c_punct = ",;:$&+=".toCharArray();
+ char[] c_reserved = "?/[]@".toCharArray();//plus punct
+
+ asciiQueryChars = new BitSet(128);
+ for (char c = 'a'; c <= 'z'; c++) asciiQueryChars.set((int) c);
+ for (char c = 'A'; c <= 'Z'; c++) asciiQueryChars.set((int) c);
+ for (char c = '0'; c <= '9'; c++) asciiQueryChars.set((int) c);
+ for (char c : c_unreserved) asciiQueryChars.set((int) c);
+ for (char c : c_punct) asciiQueryChars.set((int) c);
+ for (char c : c_reserved) asciiQueryChars.set((int) c);
+
+ asciiQueryChars.set((int) '%');//leave existing percent escapes in place
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/servlets/JolokiaConfiguredAgentServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/servlets/JolokiaConfiguredAgentServlet.java"
new file mode 100755
index 0000000..ee23f46
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/servlets/JolokiaConfiguredAgentServlet.java"
@@ -0,0 +1,133 @@
+package io.hawt.web.servlets;
+
+import org.jolokia.config.ConfigKey;
+import org.jolokia.http.AgentServlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+
+/**
+ * Decorator class around Jolokia native AgentServlet.
+ *
+ * Adds support to specify Jolokia agent configurable parameters via java system properties mechanism.
+ * This allows to provide start up time customization, without the need to alter web.xml deployment descriptor.
+ *
+ * To specify them, you need to pass the to the jvm process with "jolokia." prefix.
+ *
+ * Ex.
+ * -Djolokia.policyLocation=file:///home/fuse/my-access.xml'
+ *
+ * The supported input configuration is described in Jolokia documentation:
+ *
+ * https://jolokia.org/reference/html/agents.html#agent-war-init-params
+ */
+public class JolokiaConfiguredAgentServlet extends AgentServlet {
+ private static final transient Logger LOG = LoggerFactory.getLogger(JolokiaConfiguredAgentServlet.class);
+
+ @Override
+ public void init(ServletConfig pServletConfig) throws ServletException {
+ ServletConfigWrapper pServletConfigWrapper = null;
+
+ Properties properties = System.getProperties();
+ for (String key : properties.stringPropertyNames()) {
+ if (key.startsWith("jolokia.")) {
+ String effectiveKey = key.substring(key.indexOf(".") + 1);
+ if (containsEnum(effectiveKey)) {
+ String value = properties.getProperty(key);
+ if (value != null) {
+ if (pServletConfigWrapper == null) {
+ pServletConfigWrapper = new ServletConfigWrapper(pServletConfig);
+ }
+ LOG.info("Jolokia overridden property: [key={}, value={}]", effectiveKey, value);
+ pServletConfigWrapper.addProperty(effectiveKey, value);
+ }
+
+ }
+ }
+ }
+ if (pServletConfigWrapper != null) {
+ super.init(pServletConfigWrapper);
+ } else {
+ LOG.info("Jolokia has not found any overriden configuration property passed at launch time; Default configuration values will be used.");
+ super.init(pServletConfig);
+ }
+
+ }
+
+ class ServletConfigWrapper implements ServletConfig {
+ ServletConfig wrapped;
+ Hashtable ownProps;
+
+ public ServletConfigWrapper(ServletConfig pServletConfig) {
+ wrapped = pServletConfig;
+ ownProps = new Hashtable<>();
+ }
+
+ @Override
+ public String getServletName() {
+ return wrapped.getServletName();
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return wrapped.getServletContext();
+ }
+
+ @Override
+ public String getInitParameter(String s) {
+ if (ownProps.containsKey(s)) {
+ return ownProps.get(s);
+ }
+ return wrapped.getInitParameter(s);
+ }
+
+ @Override
+ public Enumeration getInitParameterNames() {
+ return new TwoEnumerationsWrapper(ownProps.keys(), wrapped.getInitParameterNames());
+ }
+
+ public void addProperty(String key, String value) {
+ ownProps.put(key, value);
+ }
+ }
+
+ class TwoEnumerationsWrapper implements Enumeration {
+ Enumeration a;
+ Enumeration b;
+
+ public TwoEnumerationsWrapper(Enumeration a, Enumeration b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ @Override
+ public boolean hasMoreElements() {
+ return a.hasMoreElements() || b.hasMoreElements();
+ }
+
+ @Override
+ public String nextElement() {
+ if (a.hasMoreElements()) {
+ return a.nextElement();
+ } else {
+ return b.nextElement();
+ }
+ }
+ }
+
+ public static boolean containsEnum(String test) {
+ for (ConfigKey c : ConfigKey.values()) {
+ if (c.getKeyValue().equals(test)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/servlets/SpringBatchConfigServlet.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/servlets/SpringBatchConfigServlet.java"
new file mode 100755
index 0000000..2dcaee5
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/servlets/SpringBatchConfigServlet.java"
@@ -0,0 +1,120 @@
+package io.hawt.web.servlets;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static io.hawt.web.ServletHelpers.writeEmpty;
+
+public class SpringBatchConfigServlet extends HttpServlet {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(SpringBatchConfigServlet.class);
+
+ @Override
+ public void doGet(HttpServletRequest httpServletRequest,
+ HttpServletResponse httpServletResponse) throws IOException, ServletException {
+
+ InputStream propsIn = SpringBatchConfigServlet.class.getClassLoader().getResourceAsStream("springbatch.properties");
+ httpServletResponse.setHeader("Content-type", "application/json");
+ if (propsIn == null) {
+ writeEmpty(httpServletResponse.getWriter());
+ return;
+ }
+ Properties properties = new Properties();
+ properties.load(propsIn);
+ JSONObject responseJson = new JSONObject();
+ JSONArray springBatchServersJson = new JSONArray();
+ List extends String> springBatchServers = Arrays.asList(properties.getProperty("springBatchServerList").split(","));
+ springBatchServersJson.addAll(springBatchServers);
+ responseJson.put("springBatchServerList", springBatchServersJson);
+ String res = "success";
+
+ httpServletResponse.getWriter().println(responseJson.toJSONString());
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ File file = getPropertiesFile("springbatch.properties");
+ Properties properties = getProperties(file);
+ String server = req.getParameter("server");
+ String replaceServer = req.getParameter("replaceServer");
+
+ if ((replaceServer != null && !replaceServer.isEmpty()) && (server != null && !server.isEmpty())) {
+ String[] servers = properties.getProperty("springBatchServerList").split(",");
+ List serverList = new ArrayList(Arrays.asList(servers));
+ if (serverList.contains(replaceServer)) {
+ serverList.remove(replaceServer);
+ serverList.add(server);
+ }
+ properties.setProperty("springBatchServerList", join(serverList, ","));
+ properties.store(new FileOutputStream(file), null);
+ resp.getWriter().print("updated");
+ } else if (server != null && !server.isEmpty()) {
+ properties.setProperty("springBatchServerList", properties.getProperty("springBatchServerList") + "," + server);
+ properties.store(new FileOutputStream(file), null);
+ resp.getWriter().print("added");
+ } else {
+ resp.getWriter().print("failed");
+ }
+ }
+
+ @Override
+ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ File file = getPropertiesFile("springbatch.properties");
+ Properties properties = getProperties(file);
+ String server = req.getParameter("server");
+ if (server != null && !server.isEmpty()) {
+ String[] servers = properties.getProperty("springBatchServerList").split(",");
+ List serverList = new ArrayList(Arrays.asList(servers));
+ serverList.remove(server);
+ properties.setProperty("springBatchServerList", join(serverList, ","));
+ properties.store(new FileOutputStream(file), null);
+ resp.getWriter().print("deleted");
+ } else {
+ resp.getWriter().print("failed");
+ }
+ }
+
+ private File getPropertiesFile(String name) {
+ URL propsUrl = SpringBatchConfigServlet.class.getClassLoader().getResource(name);
+ File file = null;
+ try {
+ file = new File(propsUrl.toURI());
+ } catch (URISyntaxException s) {
+ LOG.error(s.getMessage());
+ }
+ return file;
+ }
+
+ private Properties getProperties(File file) throws IOException {
+ FileInputStream propsIn = new FileInputStream(file);
+ Properties properties = new Properties();
+ properties.load(propsIn);
+ return properties;
+ }
+
+ private String join(List list, String div) {
+ StringBuffer buffer = new StringBuffer();
+ for (String e : list) {
+ buffer.append((list.size() == (list.indexOf(e) + 1)) ? e : e + div);
+ }
+ return buffer.toString();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatAuthenticationContainerDiscovery.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatAuthenticationContainerDiscovery.java"
new file mode 100755
index 0000000..ab375d9
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatAuthenticationContainerDiscovery.java"
@@ -0,0 +1,72 @@
+package io.hawt.web.tomcat;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import io.hawt.web.auth.AuthenticationConfiguration;
+import io.hawt.web.auth.AuthenticationContainerDiscovery;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * To use Apache Tomcat using its conf/tomcat-users.xml for authentication.
+ *
+ * To use this, then the {@link AuthenticationConfiguration#getRealm()} must be empty or "*". Otherwise
+ * if an explicit configured realm has been set, then regular JAAS authentication is in use.
+ */
+public class TomcatAuthenticationContainerDiscovery implements AuthenticationContainerDiscovery {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(TomcatAuthenticationContainerDiscovery.class);
+
+ private static final transient String AUTHENTICATION_CONTAINER_TOMCAT_DIGEST_ALGORITHM = "hawtio.authenticationContainerTomcatDigestAlgorithm";
+ private static final transient String AUTHENTICATION_TOMCAT_USER_LOCATION = "hawtio.tomcatUserFileLocation";
+
+ @Override
+ public String getContainerName() {
+ return "Apache Tomcat";
+ }
+
+ @Override
+ public boolean canAuthenticate(AuthenticationConfiguration configuration) {
+ if (!isEmptyOrAllRealm(configuration.getRealm())) {
+ LOG.debug("Realm explicit configured {}. {} userdata authentication integration not in use.", configuration.getRealm(), getContainerName());
+ return false;
+ }
+
+ try {
+ MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+ boolean isTomcat = server.isRegistered(new ObjectName("Catalina:type=Server"));
+ if (!isTomcat) {
+ isTomcat = server.isRegistered(new ObjectName("Tomcat:type=Server"));
+ }
+ LOG.debug("Checked for {} in JMX for {} -> {}", getContainerName(), isTomcat);
+
+ if (isTomcat) {
+ configuration.setConfiguration(new TomcatLoginContextConfiguration(System.getProperty(AUTHENTICATION_CONTAINER_TOMCAT_DIGEST_ALGORITHM, "NONE").toUpperCase(),
+ System.getProperty(AUTHENTICATION_TOMCAT_USER_LOCATION,null)));
+ configuration.setRolePrincipalClasses(TomcatPrincipal.class.getName());
+ }
+ return isTomcat;
+
+ } catch (MalformedObjectNameException e) {
+ // ignore
+ LOG.warn("Error checking in JMX for " + getContainerName() + ". This exception is ignored.", e);
+ }
+
+ return false;
+ }
+
+ /**
+ * Is the realm empty or * to denote any realm.
+ */
+ private static boolean isEmptyOrAllRealm(String realm) {
+ if (realm == null || realm.trim().isEmpty() || realm.trim().equals("*")) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatLoginContextConfiguration.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatLoginContextConfiguration.java"
new file mode 100755
index 0000000..46014b4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatLoginContextConfiguration.java"
@@ -0,0 +1,34 @@
+package io.hawt.web.tomcat;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+/**
+ * Configuration class to avoid having to deal with jaas.config files in the classpath
+ */
+public class TomcatLoginContextConfiguration extends Configuration {
+
+ private final AppConfigurationEntry entry;
+
+ public TomcatLoginContextConfiguration(final String digestAlgorithm, final String tomcatUserLocation) {
+ Map options = new HashMap<>(1);
+ options.put(TomcatUserDatabaseLoginContext.OPTION_DIGEST_ALGORITHM, digestAlgorithm);
+ options.put(TomcatUserDatabaseLoginContext.OPTION_TOMCAT_USER_LOCATION, tomcatUserLocation);
+ this.entry = new TomcatAppConfigurationEntry(Collections.unmodifiableMap(options));
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ return new AppConfigurationEntry[]{entry};
+ }
+
+ private static final class TomcatAppConfigurationEntry extends AppConfigurationEntry {
+ public TomcatAppConfigurationEntry(Map options) {
+ super("io.hawt.web.tomcat.TomcatUserDatabaseLoginContext", LoginModuleControlFlag.REQUIRED, options);
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatPrincipal.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatPrincipal.java"
new file mode 100755
index 0000000..2b2ca8c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatPrincipal.java"
@@ -0,0 +1,21 @@
+package io.hawt.web.tomcat;
+
+import java.io.Serializable;
+import java.security.Principal;
+
+/**
+ * A very simple Apache Tomcat {@link Principal}.
+ */
+public class TomcatPrincipal implements Principal, Serializable {
+
+ private final String roleName;
+
+ public TomcatPrincipal(String roleName) {
+ this.roleName = roleName;
+ }
+
+ @Override
+ public String getName() {
+ return roleName;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatUserDatabaseLoginContext.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatUserDatabaseLoginContext.java"
new file mode 100755
index 0000000..5d90af3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/java/io/hawt/web/tomcat/TomcatUserDatabaseLoginContext.java"
@@ -0,0 +1,232 @@
+package io.hawt.web.tomcat;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import io.hawt.util.Predicate;
+import io.hawt.web.auth.AuthenticationFilter;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * To use Apache Tomcat's conf/tomcat-users.xml user database as JAAS {@link javax.security.auth.login.LoginContext},
+ * so hawtio can use that for its {@link AuthenticationFilter}.
+ */
+public class TomcatUserDatabaseLoginContext implements LoginModule {
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(TomcatUserDatabaseLoginContext.class);
+ private Subject subject;
+ private CallbackHandler callbackHandler;
+ private String fileName = "conf/tomcat-users.xml";
+ private File file;
+ private String digestAlgorithm;
+
+
+ private static final Map> PASSWORD_CHECKS;
+ public static final String OPTION_DIGEST_ALGORITHM = "DIGEST_ALGORITHM";
+ public static final String OPTION_TOMCAT_USER_LOCATION = "USER_LOCATION";
+
+ static {
+ Map> temp = new HashMap<>(6);
+ temp.put(
+ "NONE",
+ new Predicate() {
+ @Override
+ public boolean evaluate(final PasswordPair passwordPair) {
+ return passwordPair.getFilePassword().equals(passwordPair.getSuppliedPassword());
+ }
+ });
+ temp.put(
+ "MD5",
+ new Predicate() {
+ @Override
+ public boolean evaluate(final PasswordPair passwordPair) {
+ return passwordPair.getFilePassword().equals(DigestUtils.md5Hex(passwordPair.getSuppliedPassword()));
+ }
+ });
+ temp.put(
+ "SHA-256",
+ new Predicate() {
+ @Override
+ public boolean evaluate(final PasswordPair passwordPair) {
+ return passwordPair.getFilePassword().equals(DigestUtils.sha256Hex(passwordPair.getSuppliedPassword()));
+ }
+ });
+ temp.put(
+ "SHA",
+ new Predicate() {
+ @Override
+ public boolean evaluate(final PasswordPair passwordPair) {
+ return passwordPair.getFilePassword().equals(DigestUtils.shaHex(passwordPair.getSuppliedPassword()));
+ }
+ });
+ temp.put(
+ "SHA-512",
+ new Predicate() {
+ @Override
+ public boolean evaluate(final PasswordPair passwordPair) {
+ return passwordPair.getFilePassword().equals(DigestUtils.sha512Hex(passwordPair.getSuppliedPassword()));
+ }
+ });
+ temp.put(
+ "SHA-384",
+ new Predicate() {
+ @Override
+ public boolean evaluate(final PasswordPair passwordPair) {
+ return passwordPair.getFilePassword().equals(DigestUtils.sha384Hex(passwordPair.getSuppliedPassword()));
+ }
+ });
+ PASSWORD_CHECKS = Collections.unmodifiableMap(temp);
+ }
+
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
+ this.subject = subject;
+ this.callbackHandler = callbackHandler;
+
+ Object customLocation = options.get(OPTION_TOMCAT_USER_LOCATION);
+ if (customLocation != null) {
+ this.file = new File(customLocation.toString(), "tomcat-users.xml");
+ }
+
+ if (file == null || ! file.exists()) {
+ String base = System.getProperty("catalina.base", ".");
+ LOG.debug("Using base directory: {}", base);
+ this.file = new File(base, fileName);
+ }
+
+ if (! file.exists()) {
+ String msg = "Cannot find Apache Tomcat user database file: " + file;
+ LOG.warn(msg);
+ throw new IllegalStateException(msg);
+ }
+
+ digestAlgorithm = options.get(OPTION_DIGEST_ALGORITHM).toString();
+
+ if (! PASSWORD_CHECKS.containsKey(digestAlgorithm)) {
+ String msg = "Invalid digest algorithm specified: " + digestAlgorithm + " (valid: " + PASSWORD_CHECKS.keySet() + ")";
+ LOG.warn(msg);
+ throw new IllegalStateException(msg);
+ }
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ // get username and password
+ Callback[] callbacks = new Callback[2];
+ callbacks[0] = new NameCallback("username");
+ callbacks[1] = new PasswordCallback("password", false);
+
+ try {
+ callbackHandler.handle(callbacks);
+ String username = ((NameCallback) callbacks[0]).getName();
+ char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
+ String password = new String(tmpPassword);
+ ((PasswordCallback) callbacks[1]).clearPassword();
+
+ LOG.debug("Getting user details for username {}", username);
+ String[] user = getUserPasswordRole(username);
+ if (user != null) {
+ if (! passwordsMatch(new PasswordPair(user[1], password))) {
+ LOG.trace("Login denied due password did not match");
+ return false;
+ }
+ String[] roles = user[2].split(",");
+ for (String role : roles) {
+ LOG.trace("User {} has role {}", username, role);
+ subject.getPrincipals().add(new TomcatPrincipal(role));
+ }
+ } else {
+ LOG.trace("Login denied due user not found");
+ return false;
+ }
+ } catch (UnsupportedCallbackException uce) {
+ LoginException le = new LoginException("Error: " + uce.getCallback().toString()
+ + " not available to gather authentication information from the user");
+ le.initCause(uce);
+ throw le;
+ } catch (Exception ioe) {
+ LoginException le = new LoginException(ioe.toString());
+ le.initCause(ioe);
+ throw le;
+ }
+
+ return true;
+ }
+
+ protected boolean passwordsMatch(PasswordPair passwordPair) {
+ return PASSWORD_CHECKS.get(digestAlgorithm).evaluate(passwordPair);
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ subject = null;
+ callbackHandler = null;
+ return true;
+ }
+
+ protected String[] getUserPasswordRole(String username) throws Exception {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document dom = builder.parse(file);
+
+ NodeList users = dom.getElementsByTagName("user");
+ for (int i = 0; i < users.getLength(); i++) {
+ Node node = users.item(i);
+ String nUsername = node.getAttributes().getNamedItem("username").getNodeValue();
+ String nPassword = node.getAttributes().getNamedItem("password").getNodeValue();
+ String nRoles = node.getAttributes().getNamedItem("roles").getNodeValue();
+ if (username.equals(nUsername)) {
+ return new String[] {username, nPassword, nRoles};
+ }
+ }
+ return null;
+ }
+
+ private static class PasswordPair {
+ private final String filePassword;
+ private final String suppliedPassword;
+
+ private PasswordPair(final String filePassword, final String suppliedPassword) {
+ this.filePassword = filePassword;
+ this.suppliedPassword = suppliedPassword;
+ }
+
+ public String getFilePassword() {
+ return filePassword;
+ }
+
+ public String getSuppliedPassword() {
+ return suppliedPassword;
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/resources/META-INF/detectors" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/resources/META-INF/detectors"
new file mode 100755
index 0000000..df449cb
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/main/resources/META-INF/detectors"
@@ -0,0 +1 @@
+io.hawt.osgi.OsgiMBeanDetector
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/jmx/JmxTreeWatcherTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/jmx/JmxTreeWatcherTest.java"
new file mode 100755
index 0000000..b0b0e31
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/jmx/JmxTreeWatcherTest.java"
@@ -0,0 +1,41 @@
+package io.hawt.jmx;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class JmxTreeWatcherTest {
+ JmxTreeWatcher treeWatcher = new JmxTreeWatcher();
+
+ @Before
+ public void init() throws Exception {
+ treeWatcher.init();
+ }
+
+ @After
+ public void destroy() throws Exception {
+ treeWatcher.destroy();
+ }
+
+ @Test
+ public void testNotificationsOnNewMBeans() throws Exception {
+ long value1 = treeWatcher.getCounter();
+
+ // now lets register a new mbean
+ About about = new About();
+ about.init();
+
+ long value2 = treeWatcher.getCounter();
+ assertCounterGreater(value1, value2);
+ about.destroy();
+
+ long value3 = treeWatcher.getCounter();
+ assertCounterGreater(value2, value3);
+ }
+
+ private void assertCounterGreater(long value1, long value2) {
+ assertTrue("Counter: " + value1 + " should be less than counter2 = " + value2, value1 < value2);
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/jmx/RBACRegistryTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/jmx/RBACRegistryTest.java"
new file mode 100755
index 0000000..b13171a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/jmx/RBACRegistryTest.java"
@@ -0,0 +1,40 @@
+package io.hawt.jmx;
+
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+public class RBACRegistryTest {
+
+ private RBACRegistry rbacRegistry = new RBACRegistry();
+
+ @Before
+ public void init() throws Exception {
+ rbacRegistry.init();
+ }
+
+ @After
+ public void destroy() throws Exception {
+ rbacRegistry.destroy();
+ }
+
+ @Test
+ public void list() throws Exception {
+ Map result = rbacRegistry.list();
+
+ assertThat(result.get("cache"), notNullValue());
+ Map> domains =
+ (Map>) result.get("domains");
+ assertThat(domains, notNullValue());
+ Map hawtioDomain = domains.get("hawtio");
+ assertThat(hawtioDomain, notNullValue());
+ assertThat(hawtioDomain.get("type=security,name=RBACRegistry"),
+ notNullValue());
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/system/ConfigManagerTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/system/ConfigManagerTest.java"
new file mode 100755
index 0000000..e01d7d5
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/system/ConfigManagerTest.java"
@@ -0,0 +1,168 @@
+package io.hawt.system;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import javax.servlet.ServletContext;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+public class ConfigManagerTest {
+
+ @Mock
+ private Context jndiContext;
+
+ @Mock
+ private ServletContext servletContext;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ TestInitialContextFactory.setCurrentContext(jndiContext);
+ System.clearProperty("hawtio.forceProperties");
+ System.clearProperty("hawtio.foo");
+ System.clearProperty(Context.INITIAL_CONTEXT_FACTORY);
+ }
+
+ @After
+ public void tearDown() {
+ System.clearProperty("hawtio.foo");
+ System.clearProperty(Context.INITIAL_CONTEXT_FACTORY);
+ }
+
+ @Test
+ public void testConstructor() {
+ new ConfigManager();
+ }
+
+ @Test
+ public void testGetNoJndiContext() {
+ System.setProperty("hawtio.foo", "bar");
+
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+
+ Assert.assertEquals("bar", underTest.get("foo", null));
+ }
+
+ @Test
+ public void testGetWithoutJndiContextWithDefaultValue() {
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+
+ Assert.assertEquals("default", underTest.get("foo", "default"));
+ }
+
+ @Test
+ public void testGetWithCustomProvider() throws Exception {
+ final ConfigManager underTest = new ConfigManager(
+ x -> "foo".equals(x) ? "bar" : null);
+ underTest.init(servletContext);
+
+ Assert.assertEquals("bar", underTest.get("foo", "default"));
+ }
+
+ @Test
+ public void testGetWithCustomProviderOverriddenBySystemProperty()
+ throws Exception {
+ System.setProperty("hawtio.foo", "system");
+ final ConfigManager underTest = new ConfigManager(
+ x -> "foo".equals(x) ? "bar" : null);
+ underTest.init(servletContext);
+
+ Assert.assertEquals("system", underTest.get("foo", "default"));
+ }
+
+ @Test
+ public void testGetWithJndiContext() throws Exception {
+ System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
+ TestInitialContextFactory.class.getName());
+ Mockito.when(jndiContext.lookup("java:comp/env")).thenReturn(jndiContext);
+ Mockito.when(jndiContext.lookup("hawtio/foo")).thenReturn("bar");
+
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+
+ Assert.assertEquals("bar", underTest.get("foo", null));
+ }
+
+ @Test
+ public void testGetWithJndiContextDefaultValue() throws Exception {
+ System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
+ TestInitialContextFactory.class.getName());
+ Mockito.when(jndiContext.lookup("java:comp/env")).thenReturn(jndiContext);
+
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+
+ Assert.assertEquals("foobar", underTest.get("foo", "foobar"));
+
+ Mockito.verify(jndiContext).lookup("hawtio/foo");
+ }
+
+ @Test
+ public void testGetWithJndiContextForceSystemProperties() throws Exception {
+ System.setProperty("hawtio.foo", "systemBar");
+ System.setProperty("hawtio.forceProperties", "true");
+ System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
+ TestInitialContextFactory.class.getName());
+
+ Mockito.when(jndiContext.lookup("java:comp/env")).thenReturn(jndiContext);
+ Mockito.when(jndiContext.lookup("hawtio/foo")).thenReturn("jndiBar");
+
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+
+ Assert.assertEquals("systemBar", underTest.get("foo", null));
+ }
+
+ @Test
+ public void testDestroyNoJndiContext() {
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+ underTest.destroy();
+
+ Mockito.verifyZeroInteractions(jndiContext);
+ }
+
+ @Test
+ public void testDestroyWithJndiContext() throws Exception {
+ Mockito.when(jndiContext.lookup("java:comp/env")).thenReturn(jndiContext);
+ System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
+ TestInitialContextFactory.class.getName());
+
+ final ConfigManager underTest = new ConfigManager();
+ underTest.init(servletContext);
+ underTest.destroy();
+
+ Mockito.verify(jndiContext).close();
+ }
+
+ public static class TestInitialContextFactory implements InitialContextFactory {
+
+ private static final ThreadLocal CTX = new ThreadLocal<>();
+
+ @Override
+ public Context getInitialContext(Hashtable, ?> environment)
+ throws NamingException {
+ return CTX.get();
+ }
+
+ public static void setCurrentContext(Context context) {
+ CTX.set(context);
+ }
+
+ public static void clearCurrentContext() {
+ CTX.remove();
+ }
+
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/system/RBACRestrictorTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/system/RBACRestrictorTest.java"
new file mode 100755
index 0000000..d1cceca
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/system/RBACRestrictorTest.java"
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2016 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.system;
+
+import java.util.Arrays;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+import io.hawt.jmx.JMXSecurity;
+import org.jolokia.config.Configuration;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public class RBACRestrictorTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RBACRestrictorTest.class);
+
+ private JMXSecurity mockJMXSecurity;
+
+ @Before
+ public void setUp() throws Exception {
+ this.mockJMXSecurity = new MockJMXSecurity();
+ this.mockJMXSecurity.init();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ this.mockJMXSecurity.destroy();
+ this.mockJMXSecurity = null;
+ }
+
+ @Test
+ public void noJMXSecurityMBean() throws Exception {
+ // make sure no JMXSecurity MBean is registered
+ this.mockJMXSecurity.destroy();
+ RBACRestrictor restrictor = new RBACRestrictor(new Configuration());
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=Test"), "anyMethod(java.lang.String)"), is(true));
+ assertThat(restrictor.isAttributeReadAllowed(new ObjectName("java.lang:type=Runtime"), "VmName"), is(true));
+ assertThat(restrictor.isAttributeWriteAllowed(new ObjectName("java.lang:type=Runtime"), "VmName"), is(true));
+ }
+
+ @Test
+ public void isOperationAllowed() throws Exception {
+ RBACRestrictor restrictor = new RBACRestrictor(new Configuration());
+
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=Test"), "allowed()"), is(true));
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=Test"), "notAllowed()"), is(false));
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=Test"), "error()"), is(false));
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=NoSuchType"), "noInstance()"), is(false));
+
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=Test"), "allowed(boolean,long,java.lang.String)"), is(true));
+ assertThat(restrictor.isOperationAllowed(new ObjectName("hawtio:type=Test"), "notAllowed(boolean,long,java.lang.String)"), is(false));
+ }
+
+ @Test
+ public void isAttributeReadAllowed() throws Exception {
+ RBACRestrictor restrictor = new RBACRestrictor(new Configuration());
+ assertThat(restrictor.isAttributeReadAllowed(new ObjectName("java.lang:type=Runtime"), "VmName"), is(true));
+ assertThat(restrictor.isAttributeReadAllowed(new ObjectName("java.lang:type=Memory"), "Verbose"), is(true));
+ assertThat(restrictor.isAttributeReadAllowed(new ObjectName("java.lang:type=Runtime"), "VmVersion"), is(false));
+ assertThat(restrictor.isAttributeReadAllowed(new ObjectName("java.lang:type=Runtime"), "xxx"), is(false));
+ assertThat(restrictor.isAttributeReadAllowed(new ObjectName("hawtio:type=NoSuchType"), "Whatever"), is(false));
+ }
+
+ @Test
+ public void isAttributeWriteAllowed() throws Exception {
+ RBACRestrictor restrictor = new RBACRestrictor(new Configuration());
+ assertThat(restrictor.isAttributeWriteAllowed(new ObjectName("java.lang:type=Memory"), "Verbose"), is(true));
+ assertThat(restrictor.isAttributeWriteAllowed(new ObjectName("java.lang:type=Runtime"), "VmVersion"), is(false));
+ assertThat(restrictor.isAttributeWriteAllowed(new ObjectName("java.lang:type=Runtime"), "xxx"), is(false));
+ assertThat(restrictor.isAttributeWriteAllowed(new ObjectName("hawtio:type=NoSuchType"), "Whatever"), is(false));
+ }
+
+ private class MockJMXSecurity extends JMXSecurity {
+ @Override
+ public boolean canInvoke(String objectName, String methodName) throws Exception {
+ return false;
+ }
+
+ @Override
+ public boolean canInvoke(String objectName, String methodName, String[] argTypes) throws Exception {
+ LOG.debug("{}, {}, {}", objectName, methodName, Arrays.asList(argTypes));
+ if (argTypes.length == 0) {
+ if ("hawtio:type=Test".equals(objectName) && "allowed".equals(methodName)) {
+ return true;
+ }
+ if ("hawtio:type=Test".equals(objectName) && "error".equals(methodName)) {
+ throw new Exception();
+ }
+ if ("hawtio:type=NoSuchType".equals(objectName) && "noInstance".equals(methodName)) {
+ throw new InstanceNotFoundException(objectName);
+ }
+ if ("java.lang:type=Runtime".equals(objectName) && "getVmName".equals(methodName)) {
+ return true;
+ }
+ if ("java.lang:type=Memory".equals(objectName) && "isVerbose".equals(methodName)) {
+ return true;
+ }
+ } else {
+ if ("hawtio:type=Test".equals(objectName) && "allowed".equals(methodName) && argTypes.length == 3
+ && "boolean".equals(argTypes[0]) && "long".equals(argTypes[1]) && "java.lang.String".equals(argTypes[2])) {
+ return true;
+ }
+ if ("java.lang:type=Memory".equals(objectName) && "setVerbose".equals(methodName) && argTypes.length == 1
+ && "boolean".equals(argTypes[0])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected String getDefaultObjectName() {
+ return "hawtio:type=security,area=jmx,name=MockJMXSecurity";
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/RelativeRequestUriTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/RelativeRequestUriTest.java"
new file mode 100755
index 0000000..5caf94c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/RelativeRequestUriTest.java"
@@ -0,0 +1,93 @@
+package io.hawt.web;
+
+import javax.servlet.http.HttpServletRequest;
+
+import io.hawt.web.auth.RelativeRequestUri;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(Parameterized.class)
+public class RelativeRequestUriTest {
+
+ @Parameters
+ public static Object[][] params() {
+ return new Object[][] { // @formatter:off
+ { "", 0, "", "", "", new String[0] },
+ { "", 1, "", "", "", new String[0] },
+ { "", 0, "/", "", "", new String[0] },
+ { "", 1, "/", "", "", new String[0] },
+ { "", 0, "/a", "/", "a", new String[] { "a" } },
+ { "", 0, "/a/b", "/", "a/b", new String[] { "a", "b" } },
+ { "", 1, "/a", "/a", "", new String[0] },
+ { "", 1, "/a/b", "/a/", "b", new String[] { "b" } },
+ { "", 2, "/a/b", "/a/b", "", new String[0] },
+ { "", 0, "/a/b/c", "/", "a/b/c", new String[] { "a", "b", "c"} },
+ { "", 1, "/a/b/c", "/a/", "b/c", new String[] { "b", "c"} },
+ { "", 2, "/a/b/c", "/a/b/", "c", new String[] { "c" } },
+ { "", 3, "/a/b/c", "/a/b/c", "", new String[0] },
+ { "/a", 0, "", "", "", new String[0] },
+ { "/a", 1, "", "", "", new String[0] },
+ { "/a", 0, "/", "", "", new String[0] },
+ { "/a", 1, "/", "", "", new String[0] },
+ { "/a", 0, "/a", "/a", "", new String[0] },
+ { "/a", 0, "/a/b", "/a/", "b", new String[] { "b" } },
+ { "/a", 1, "/a", "/a", "", new String[0] },
+ { "/a", 1, "/a/b", "/a/b", "", new String[0] },
+ { "/a", 2, "/a/b", "/a/b", "", new String[0] },
+ { "/a", 0, "/a/b/c", "/a/", "b/c", new String[] { "b", "c" } },
+ { "/a", 1, "/a/b/c", "/a/b/", "c", new String[] { "c" } },
+ { "/a", 2, "/a/b/c", "/a/b/c", "", new String[0] },
+ { "/a", 3, "/a/b/c", "/a/b/c", "", new String[0] },
+ }; // @formatter:on
+ }
+
+ @Mock
+ private HttpServletRequest request;
+
+ private final String contextPath;
+ private final int pathIndex;
+ private final String requestUri;
+ private final String expectedPrefix;
+ private final String expectedUri;
+ private final String[] expectedComponents;
+ private final String expectedLastComponent;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Mockito.when(request.getContextPath()).thenReturn(contextPath);
+ Mockito.when(request.getRequestURI()).thenReturn(requestUri);
+ }
+
+ public RelativeRequestUriTest(final String contextPath, final int pathIndex,
+ final String requestUri, final String expectedPrefix,
+ final String expectedUri, final String[] expectedComponents) {
+ this.contextPath = contextPath;
+ this.pathIndex = pathIndex;
+ this.requestUri = requestUri;
+ this.expectedPrefix = expectedPrefix;
+ this.expectedUri = expectedUri;
+ this.expectedComponents = expectedComponents;
+ this.expectedLastComponent = expectedComponents.length == 0 ? null
+ : expectedComponents[expectedComponents.length - 1];
+ }
+
+ @Test
+ public void test() {
+ final RelativeRequestUri underTest = new RelativeRequestUri(request,
+ pathIndex);
+ Assert.assertEquals(expectedPrefix, underTest.getPrefix());
+ Assert.assertEquals(expectedUri, underTest.getUri());
+ Assert.assertEquals(expectedUri, underTest.toString());
+ Assert.assertArrayEquals(expectedComponents, underTest.getComponents());
+ Assert.assertEquals(expectedLastComponent, underTest.getLastComponent());
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/ServletHelpersTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/ServletHelpersTest.java"
new file mode 100755
index 0000000..bcda7e4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/ServletHelpersTest.java"
@@ -0,0 +1,26 @@
+package io.hawt.web;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+
+import org.json.JSONObject;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+
+public class ServletHelpersTest {
+
+ @Test
+ public void readObject() throws Exception {
+ String data = "{ string: 'text', number: 2, boolean: true }";
+ JSONObject json = ServletHelpers.readObject(
+ new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data.getBytes()))));
+ assertThat(json.get("string"), equalTo("text"));
+ assertThat(json.get("number"), equalTo(2));
+ assertThat(json.get("boolean"), equalTo(true));
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/auth/LoginRedirectFilterTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/auth/LoginRedirectFilterTest.java"
new file mode 100755
index 0000000..b02bfa8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/auth/LoginRedirectFilterTest.java"
@@ -0,0 +1,47 @@
+package io.hawt.web.auth;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class LoginRedirectFilterTest {
+
+ private LoginRedirectFilter loginRedirectFilter;
+ private FilterConfig filterConfig;
+ private ServletContext servletContext;
+
+ @Before
+ public void setUp() {
+ filterConfig = mock(FilterConfig.class);
+ servletContext = mock(ServletContext.class);
+ }
+
+ @Test
+ public void shouldTestSecuredPaths() throws Exception {
+ loginRedirectFilter = new LoginRedirectFilter();
+ when(filterConfig.getServletContext()).thenReturn(servletContext);
+ loginRedirectFilter.init(filterConfig);
+ assertTrue(loginRedirectFilter.isSecuredPath("/d"));
+ assertTrue(loginRedirectFilter.isSecuredPath("/e/f"));
+ assertFalse(loginRedirectFilter.isSecuredPath("/auth/login"));
+ assertFalse(loginRedirectFilter.isSecuredPath("/auth/logout"));
+ }
+
+ @Test
+ public void customizedUnsecuredPaths() throws Exception {
+ String[] unsecuredPaths = {"/hawtio/auth", "/hawtio/secret/content"};
+ loginRedirectFilter = new LoginRedirectFilter(unsecuredPaths);
+
+ when(filterConfig.getServletContext()).thenReturn(servletContext);
+ loginRedirectFilter.init(filterConfig);
+ assertTrue(loginRedirectFilter.isSecuredPath("/d"));
+ assertTrue(loginRedirectFilter.isSecuredPath("/e/f"));
+ assertFalse(loginRedirectFilter.isSecuredPath("/hawtio/auth/login"));
+ assertFalse(loginRedirectFilter.isSecuredPath("/hawtio/secret/content/secure"));
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/auth/RedirectorTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/auth/RedirectorTest.java"
new file mode 100755
index 0000000..dbce226
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/auth/RedirectorTest.java"
@@ -0,0 +1,55 @@
+package io.hawt.web.auth;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RedirectorTest {
+
+ private Redirector redirector;
+ private HttpServletRequest request;
+ private HttpServletResponse response;
+ private ServletContext servletContext;
+
+ @Before
+ public void setUp() {
+ redirector = new Redirector();
+ redirector.setApplicationContextPath("/application-context-path");
+ request = mock(HttpServletRequest.class);
+ response = mock(HttpServletResponse.class);
+ servletContext = mock(ServletContext.class);
+
+ when(request.getServerName()).thenReturn("server01");
+ when(request.getServerPort()).thenReturn(9000);
+ when(request.getContextPath()).thenReturn("/context-path");
+ when(request.getServletContext()).thenReturn(servletContext);
+ }
+
+ @Test
+ public void shouldRedirectToRelativeUrlByDefault() throws Exception {
+ // given
+ when(servletContext.getInitParameter("scheme")).thenReturn(null);
+ // when
+ redirector.doRedirect(request, response, "/path");
+ // then
+ verify(response).sendRedirect("/context-path/application-context-path/path");
+ }
+
+ @Test
+ public void shouldRedirectToAbsoluteUrlWhenSchemeIsConfigured() throws Exception {
+ // given
+ when(servletContext.getInitParameter("scheme")).thenReturn("https");
+ // when
+ redirector.doRedirect(request, response, "/path");
+ // then
+ verify(response).sendRedirect("https://server01:9000/context-path/application-context-path/path");
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/filters/BaseTagHrefFilterTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/filters/BaseTagHrefFilterTest.java"
new file mode 100755
index 0000000..0f0beaf
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/filters/BaseTagHrefFilterTest.java"
@@ -0,0 +1,113 @@
+package io.hawt.web.filters;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import static io.hawt.web.filters.BaseTagHrefFilter.PARAM_APPLICATION_CONTEXT_PATH;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BaseTagHrefFilterTest {
+
+ private BaseTagHrefFilter filter;
+ private FilterConfig filterConfig;
+ private ServletContext servletContext;
+ private HttpServletRequest servletRequest;
+ private HttpServletResponse servletResponse;
+ private ServletOutputStream outputStream;
+ private FilterChain filterChain;
+
+ @Before
+ public void setUp() {
+ filter = new BaseTagHrefFilter();
+ filterConfig = mock(FilterConfig.class);
+ servletContext = mock(ServletContext.class);
+ servletRequest = mock(HttpServletRequest.class);
+ servletResponse = mock(HttpServletResponse.class);
+ outputStream = mock(ServletOutputStream.class);
+ filterChain = mock(FilterChain.class);
+ }
+
+ @Test
+ public void filterWithDefaultContextPath() throws Exception {
+ assertFilteredContentContainsBaseHref("/hawtio", "/hawtio/");
+ }
+
+ @Test
+ public void filterWithNullContextPath() throws Exception {
+ assertFilteredContentContainsBaseHref(null, "/");
+ }
+
+ @Test
+ public void filterWithEmptyContextPath() throws Exception {
+ assertFilteredContentContainsBaseHref("", "/");
+ }
+
+ @Test
+ public void filterWithCustomContextPaths() throws Exception {
+ assertFilteredContentContainsBaseHref("/foo", "/foo/");
+ assertFilteredContentContainsBaseHref("/foo/bar", "/foo/bar/");
+ assertFilteredContentContainsBaseHref("/foo/bar/cheese", "/foo/bar/cheese/");
+ }
+
+ @Test
+ public void filterWithSpringBootManagementContextPath() throws Exception {
+ assertFilteredContentContainsBaseHref("/management", "text/html; charset=utf-8", "/hawtio", "/hawtio/management/");
+ }
+
+ @Test
+ public void filterWithCustomContextPathAndContentTypeApplicationJson() throws Exception {
+ assertFilteredContentContainsBaseHref(null, "application/json", "/foo", "/hawtio/");
+ }
+
+ @Test
+ public void filterWithManagementContextPathAndNullContextPath() throws Exception {
+ assertFilteredContentContainsBaseHref("/management", "text/html; charset=utf-8", null, "/management/");
+ }
+
+ private void assertFilteredContentContainsBaseHref(String contextPath, String expectedBaseTagHref) throws Exception {
+ assertFilteredContentContainsBaseHref(null, "text/html; charset=utf-8", contextPath, expectedBaseTagHref);
+ }
+
+ private void assertFilteredContentContainsBaseHref(String applicationContextPath, String contentType, String contextPath, String expectedBaseTagHref) throws Exception {
+ final String originalHtml = readHtml();
+ final String expectedHtml = originalHtml.replace("/hawtio/", expectedBaseTagHref);
+
+ when(filterConfig.getServletContext()).thenReturn(servletContext);
+ when(filterConfig.getInitParameter(PARAM_APPLICATION_CONTEXT_PATH)).thenReturn(applicationContextPath);
+ when(servletContext.getContextPath()).thenReturn(contextPath);
+ when(servletResponse.getOutputStream()).thenReturn(outputStream);
+ when(servletResponse.getContentType()).thenReturn(contentType);
+
+ filter.init(filterConfig);
+ filter.doFilter(servletRequest, servletResponse, new MockFilterChain());
+
+ verify(outputStream).write(expectedHtml.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private String readHtml() throws IOException {
+ return IOUtils.toString(BaseTagHrefFilterTest.class.getResourceAsStream("index.html"));
+ }
+
+ private class MockFilterChain implements FilterChain {
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException, ServletException {
+ servletResponse.getOutputStream().write(readHtml().getBytes());
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/filters/ContentSecurityPolicyFilterTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/filters/ContentSecurityPolicyFilterTest.java"
new file mode 100755
index 0000000..7d1d22d
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/filters/ContentSecurityPolicyFilterTest.java"
@@ -0,0 +1,85 @@
+package io.hawt.web.filters;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import io.hawt.system.ConfigManager;
+import io.hawt.web.auth.keycloak.KeycloakServlet;
+
+public class ContentSecurityPolicyFilterTest {
+
+ private ContentSecurityPolicyFilter contentSecurityPolicyFilter;
+ private FilterConfig filterConfig;
+ private ServletContext servletContext;
+ private ConfigManager configManager;
+ private HttpServletRequest request;
+ private HttpServletResponse response;
+ private String keycloakConfigFile;
+
+ @Before
+ public void setUp() {
+ contentSecurityPolicyFilter = new ContentSecurityPolicyFilter();
+ filterConfig = mock(FilterConfig.class);
+ servletContext = mock(ServletContext.class);
+ configManager = mock(ConfigManager.class);
+ request = mock(HttpServletRequest.class);
+ response = mock(HttpServletResponse.class);
+ keycloakConfigFile = getClass().getClassLoader().getResource("keycloak-hawtio-client.json").getFile();
+
+ when(filterConfig.getServletContext()).thenReturn(servletContext);
+ when(servletContext.getAttribute("ConfigManager")).thenReturn(configManager);
+
+ System.clearProperty(KeycloakServlet.HAWTIO_KEYCLOAK_CLIENT_CONFIG);
+ }
+
+ @Test
+ public void shouldSetHeader() throws Exception {
+ // given
+ contentSecurityPolicyFilter.init(filterConfig);
+ // when
+ contentSecurityPolicyFilter.addHeaders(request, response);
+ // then
+ verify(response).addHeader("Content-Security-Policy",
+ "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
+ + "style-src 'self' 'unsafe-inline'; font-src 'self' data:; connect-src 'self'; "
+ + "frame-src 'self'");
+ }
+
+ @Test
+ public void shouldSetHeaderWithKeycloakServerWhenConfigParameterIsSet() throws Exception {
+ // given
+ when(configManager.get(KeycloakServlet.KEYCLOAK_CLIENT_CONFIG, null)).thenReturn(keycloakConfigFile);
+ contentSecurityPolicyFilter.init(filterConfig);
+ // when
+ contentSecurityPolicyFilter.addHeaders(request, response);
+ // then
+ verify(response).addHeader("Content-Security-Policy",
+ "default-src 'self'; script-src 'self' localhost:8180 'unsafe-inline' 'unsafe-eval'; "
+ + "style-src 'self' 'unsafe-inline'; font-src 'self' data:; "
+ + "connect-src 'self' localhost:8180; frame-src 'self' localhost:8180");
+ }
+
+ @Test
+ public void shouldSetHeaderWithKeycloakServerWhenSystemPropertyIsSet() throws Exception {
+ // given
+ System.setProperty(KeycloakServlet.HAWTIO_KEYCLOAK_CLIENT_CONFIG, keycloakConfigFile);
+ contentSecurityPolicyFilter.init(filterConfig);
+ // when
+ contentSecurityPolicyFilter.addHeaders(request, response);
+ // then
+ verify(response).addHeader("Content-Security-Policy",
+ "default-src 'self'; script-src 'self' localhost:8180 'unsafe-inline' 'unsafe-eval'; "
+ + "style-src 'self' 'unsafe-inline'; font-src 'self' data:; "
+ + "connect-src 'self' localhost:8180; frame-src 'self' localhost:8180");
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/proxy/ProxyDetailsTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/proxy/ProxyDetailsTest.java"
new file mode 100755
index 0000000..7f48c9a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/java/io/hawt/web/proxy/ProxyDetailsTest.java"
@@ -0,0 +1,283 @@
+package io.hawt.web.proxy;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ProxyDetailsTest {
+
+ @Test
+ public void testPathInfoWithUserPasswordPort() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/admin:admin@localhost/8181/jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", "admin", details.getUserName());
+ assertEquals("getPassword()", "admin", details.getPassword());
+ assertEquals("getHost()", "localhost", details.getHost());
+ assertEquals("getHostAndPort()", "localhost:8181", details.getHostAndPort());
+ assertEquals("getPort()", 8181, details.getPort());
+ assertEquals("getProxyPath()", "/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "http", details.getScheme());
+ assertEquals("getFullProxyUrl()", "http://localhost:8181/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testPathInfoWithUserPasswordDefaultPort() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/admin:admin@localhost//jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", "admin", details.getUserName());
+ assertEquals("getPassword()", "admin", details.getPassword());
+ assertEquals("getHost()", "localhost", details.getHost());
+ assertEquals("getHostAndPort()", "localhost", details.getHostAndPort());
+ assertEquals("getPort()", 80, details.getPort());
+ assertEquals("getProxyPath()", "/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "http", details.getScheme());
+ assertEquals("getFullProxyUrl()", "http://localhost/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testPathInfoWithDefaultPort() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/localhost//jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "localhost", details.getHost());
+ assertEquals("getHostAndPort()", "localhost", details.getHostAndPort());
+ assertEquals("getPort()", 80, details.getPort());
+ assertEquals("getProxyPath()", "/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "http", details.getScheme());
+ assertEquals("getFullProxyUrl()", "http://localhost/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testPathInfoWithPort() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/localhost/90/jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "localhost", details.getHost());
+ assertEquals("getHostAndPort()", "localhost:90", details.getHostAndPort());
+ assertEquals("getPort()", 90, details.getPort());
+ assertEquals("getProxyPath()", "/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "http", details.getScheme());
+ assertEquals("getFullProxyUrl()", "http://localhost:90/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testPathInfoWithWhitespace() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/http/localhost/10001/jolokia/read/java.lang:type=MemoryManager,name=Metaspace Manager/Name");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getFullProxyUrl()", "http://localhost:10001/jolokia/read/java.lang:type=MemoryManager,name=Metaspace%20Manager/Name", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testDefaultPort() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/somerest-davsclaus2.rhcloud.com/cxf/crm/customerservice/customers/123");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "somerest-davsclaus2.rhcloud.com", details.getHost());
+ assertEquals("getHostAndPort()", "somerest-davsclaus2.rhcloud.com", details.getHostAndPort());
+ assertEquals("getPort()", 80, details.getPort());
+ assertEquals("getProxyPath()", "/cxf/crm/customerservice/customers/123", details.getProxyPath());
+ assertEquals("getScheme()", "http", details.getScheme());
+ assertEquals("getFullProxyUrl()", "http://somerest-davsclaus2.rhcloud.com/cxf/crm/customerservice/customers/123", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testHttpsUrl() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://www.myhost.com/443/myApp/jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com:443", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com:443/myApp/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ @Ignore("auth-info not supported")
+ public void testHttpsWithCredentialsUrl() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://test:user@www.myhost.com/443/myApp/jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", "test", details.getUserName());
+ assertEquals("getPassword()", "user", details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com/myApp/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testHttpsUrlWithNoPort() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://www.myhost.com/myApp/jolokia/");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com/myApp/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ @Ignore("Mock code must support getParameterNames/getParameterValues")
+ public void testWithQueryString() throws Exception {
+
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://www.myhost.com/myApp/jolokia/");
+ when(mockReq.getQueryString()).thenReturn("foo=bar");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com/myApp/jolokia/?foo=bar", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testQueryStringWithIgnoredParameter() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://www.myhost.com/myApp/jolokia/");
+ when(mockReq.getQueryString()).thenReturn("url=bar");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com/myApp/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testQueryStringWithMultipleIgnoredParameters() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://www.myhost.com/myApp/jolokia/");
+ when(mockReq.getQueryString()).thenReturn("url=bar&_user=test");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com/myApp/jolokia/", details.getFullProxyUrl());
+ }
+
+ @Test
+ @Ignore("Mock code must support getParameterNames/getParameterValues")
+ public void testQueryStringWithMultipleIgnoredAndValidParameters() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo()).thenReturn("/https://www.myhost.com/myApp/jolokia/");
+ when(mockReq.getQueryString()).thenReturn("url=bar&search=1234&_user=test&page=4");
+
+ ProxyDetails details = new ProxyDetails(mockReq);
+
+ assertEquals("getUserName()", null, details.getUserName());
+ assertEquals("getPassword()", null, details.getPassword());
+ assertEquals("getHost()", "www.myhost.com", details.getHost());
+ assertEquals("getHostAndPort()", "www.myhost.com", details.getHostAndPort());
+ assertEquals("getPort()", 443, details.getPort());
+ assertEquals("getProxyPath()", "/myApp/jolokia/", details.getProxyPath());
+ assertEquals("getScheme()", "https", details.getScheme());
+ assertEquals("getFullProxyUrl()", "https://www.myhost.com/myApp/jolokia/?search=1234&page=4", details.getFullProxyUrl());
+ }
+
+ @Test
+ public void testIsAllowed() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo())
+ .thenReturn("/localhost/9000/jolokia/")
+ .thenReturn("/localhost:8181/jolokia/")
+ .thenReturn("/www.myhost.com/jolokia/")
+ .thenReturn("/myhost1.com/jolokia/")
+ .thenReturn("/myhost22.com/jolokia/")
+ .thenReturn("/www.banned.com/jolokia/");
+
+ Set whitelist = new HashSet<>(Arrays.asList("localhost", "www.myhost.com"));
+ List regexWhitelist = Collections.singletonList(Pattern.compile("myhost[0-9]+\\.com"));
+ ProxyDetails details1 = new ProxyDetails(mockReq);
+ ProxyDetails details2 = new ProxyDetails(mockReq);
+ ProxyDetails details3 = new ProxyDetails(mockReq);
+ ProxyDetails details4 = new ProxyDetails(mockReq);
+ ProxyDetails details5 = new ProxyDetails(mockReq);
+ ProxyDetails details6 = new ProxyDetails(mockReq);
+ assertTrue("localhost/9000", details1.isAllowed(whitelist));
+ assertTrue("localhost:8181", details2.isAllowed(whitelist));
+ assertTrue("www.myhost.com", details3.isAllowed(whitelist));
+ assertTrue("myhost1.com", details4.isAllowed(regexWhitelist));
+ assertTrue("myhost22.com", details5.isAllowed(regexWhitelist));
+ assertFalse("www.banned.com", details6.isAllowed(whitelist));
+ }
+
+ @Test
+ public void testIsAllowedWithAllowAll() throws Exception {
+ HttpServletRequest mockReq = mock(HttpServletRequest.class);
+ when(mockReq.getPathInfo())
+ .thenReturn("/localhost/9000/jolokia/")
+ .thenReturn("/www.myhost.com/jolokia/")
+ .thenReturn("/www.banned.com/jolokia/");
+
+ Set whitelist = new HashSet<>(Arrays.asList("*"));
+ ProxyDetails details1 = new ProxyDetails(mockReq);
+ ProxyDetails details2 = new ProxyDetails(mockReq);
+ ProxyDetails details3 = new ProxyDetails(mockReq);
+ assertTrue("localhost", details1.isAllowed(whitelist));
+ assertTrue("www.myhost.com", details2.isAllowed(whitelist));
+ assertTrue("www.banned.com", details3.isAllowed(whitelist));
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/io/hawt/web/filters/index.html" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/io/hawt/web/filters/index.html"
new file mode 100755
index 0000000..5811e3e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/io/hawt/web/filters/index.html"
@@ -0,0 +1,11 @@
+
+
+
+
+ hawtio console
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/keycloak-hawtio-client.json" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/keycloak-hawtio-client.json"
new file mode 100755
index 0000000..1c5dcd0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/keycloak-hawtio-client.json"
@@ -0,0 +1,5 @@
+{
+ "url": "http://localhost:8180/auth",
+ "clientId": "hawtio-client",
+ "realm": "fuse7karaf"
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..5d0efb1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-system/src/test/resources/log4j.properties"
@@ -0,0 +1,19 @@
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, stdout, out
+
+#log4j.logger.io.hawt.introspect=DEBUG
+#log4j.logger.io.hawt.web=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/test.log
+log4j.appender.out.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/pom.xml"
new file mode 100755
index 0000000..a847a30
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/pom.xml"
@@ -0,0 +1,36 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-util
+ ${project.artifactId}
+ hawtio :: hawtio-util
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ test
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Closeables.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Closeables.java"
new file mode 100755
index 0000000..88c1b60
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Closeables.java"
@@ -0,0 +1,20 @@
+package io.hawt.util;
+
+import java.io.Closeable;
+
+public final class Closeables {
+
+ private Closeables() {
+ //Utility Class
+ }
+
+ public static void closeQuietly(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (Exception ex) {
+ //ignore
+ }
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/FileFilters.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/FileFilters.java"
new file mode 100755
index 0000000..55fd9fa
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/FileFilters.java"
@@ -0,0 +1,101 @@
+package io.hawt.util;
+
+import java.io.File;
+import java.io.FileFilter;
+
+/**
+ * A number of helper functions for creating {@link FileFilter} objects on a {@link File} object.
+ */
+public class FileFilters {
+ private static final FileFilter TRUE_FILTER = new FileFilter() {
+ @Override
+ public String toString() {
+ return "TrueFileFilter";
+ }
+
+ @Override
+ public boolean accept(File pathname) {
+ return true;
+ }
+ };
+
+ public static FileFilter createFileFilter(String wildcard) {
+ if (Strings.isNotBlank(wildcard)) {
+ int idx = wildcard.indexOf('*');
+ if (idx < 0) {
+ return nameEqualsFilter(wildcard);
+ }
+ int lastIdx = wildcard.lastIndexOf(idx);
+ if (lastIdx < 0) {
+ lastIdx = idx;
+ }
+ FileFilter endsWith = nameEndsWithFilter(wildcard.substring(lastIdx + 1));
+ if (idx <= 0) {
+ return endsWith;
+ } else {
+ return andFilter(nameStartsWithFilter(wildcard.substring(0, idx)), endsWith);
+ }
+ }
+ return trueFilter();
+ }
+
+ public static FileFilter nameEqualsFilter(final String name) {
+ return new FileFilter() {
+ @Override
+ public String toString() {
+ return "FileNameEqualsFilter(" + name + ")";
+ }
+
+ @Override
+ public boolean accept(File file) {
+ return name.equals(file.getName());
+ }
+ };
+ }
+
+ public static FileFilter nameStartsWithFilter(final String name) {
+ return new FileFilter() {
+ @Override
+ public String toString() {
+ return "FileNameStartsWithFilter(" + name + ")";
+ }
+
+ @Override
+ public boolean accept(File file) {
+ return file.getName().startsWith(name);
+ }
+ };
+ }
+
+ public static FileFilter nameEndsWithFilter(final String name) {
+ return new FileFilter() {
+ @Override
+ public String toString() {
+ return "FileNameEndsWithFilter(" + name + ")";
+ }
+
+ @Override
+ public boolean accept(File file) {
+ return file.getName().endsWith(name);
+ }
+ };
+ }
+
+ public static FileFilter andFilter(final FileFilter filter1, final FileFilter filter2) {
+ return new FileFilter() {
+ @Override
+ public String toString() {
+ return "AndFilter(" + filter1 + " && " + filter2 + ")";
+ }
+
+ @Override
+ public boolean accept(File file) {
+ return filter1.accept(file) && filter2.accept(file);
+ }
+ };
+ }
+
+ public static FileFilter trueFilter() {
+ return TRUE_FILTER;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/FileLocker.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/FileLocker.java"
new file mode 100755
index 0000000..de663e0
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/FileLocker.java"
@@ -0,0 +1,45 @@
+package io.hawt.util;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A simple API to a file lock
+ */
+public class FileLocker {
+ private final File lockFile;
+
+ /**
+ * Attempts to grab the lock for the given file, returning a FileLock if
+ * the lock has been created; otherwise it returns null
+ */
+ public static FileLocker getLock(File lockFile) {
+ lockFile.getParentFile().mkdirs();
+ if (!lockFile.exists()) {
+ try {
+ IOHelper.write(lockFile, "I have the lock!");
+ lockFile.deleteOnExit();
+ return new FileLocker(lockFile);
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ return null;
+
+ }
+
+ public FileLocker(File lockFile) {
+ this.lockFile = lockFile;
+ }
+
+ @Override
+ public String toString() {
+ return "FileLock(" + lockFile + ")";
+ }
+
+ public void destroy() {
+ if (lockFile.exists()) {
+ lockFile.delete();
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Files.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Files.java"
new file mode 100755
index 0000000..e2261b9
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Files.java"
@@ -0,0 +1,186 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class Files {
+ private static final transient Logger LOG = LoggerFactory.getLogger(Files.class);
+
+ private static final int BUFFER_SIZE = 8192;
+
+ /**
+ * Copy the source {@link File} to the target {@link File}.
+ */
+ public static void copy(File source, File target) throws IOException {
+ if (!source.exists()) {
+ throw new FileNotFoundException("Source file not found:" + source.getAbsolutePath());
+ }
+
+ if (!target.exists() && !target.getParentFile().exists() && !target.getParentFile().mkdirs()) {
+ throw new IOException("Can't create target directory:" + target.getParentFile().getAbsolutePath());
+ }
+ FileInputStream is = new FileInputStream(source);
+ FileOutputStream os = new FileOutputStream(target);
+ IOHelper.copy(is, os);
+ }
+
+
+ /**
+ * Recursively deletes the given file whether its a file or directory returning the number
+ * of files deleted
+ */
+ public static int recursiveDelete(File file) {
+ int answer = 0;
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File child : files) {
+ answer += recursiveDelete(child);
+ }
+ }
+ }
+ if (file.delete()) {
+ answer += 1;
+ }
+ return answer;
+ }
+
+
+ public static String getRelativePath(File rootDir, File file) throws IOException {
+ String rootPath = rootDir.getCanonicalPath();
+ String fullPath = file.getCanonicalPath();
+ if (fullPath.startsWith(rootPath)) {
+ return fullPath.substring(rootPath.length());
+ } else {
+ return fullPath;
+ }
+ }
+
+ /**
+ * Reads a {@link File} and returns the data as a byte array
+ */
+ public static byte[] readBytes(File file) throws IOException {
+ FileInputStream fis = null;
+ ByteArrayOutputStream bos = null;
+ if (file == null) {
+ throw new FileNotFoundException("No file specified");
+ }
+ try {
+ fis = new FileInputStream(file);
+ bos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int remaining;
+ while ((remaining = fis.read(buffer)) > 0) {
+ bos.write(buffer, 0, remaining);
+ }
+ return bos.toByteArray();
+ } finally {
+ Closeables.closeQuietly(fis);
+ Closeables.closeQuietly(bos);
+ }
+ }
+
+ public static String getMimeType(File file) {
+ try {
+ String answer = java.nio.file.Files.probeContentType(file.toPath());
+ if (Strings.isNotBlank(answer)) {
+ return answer;
+ }
+ } catch (Throwable e) {
+ LOG.warn("Could not find mime type of " + file + ". " + e, e);
+ }
+ if (file.isDirectory()) {
+ return "application/zip";
+ }
+ String fileName = file.getName();
+ if (fileName.endsWith(".xml")) {
+ return "application/xml";
+ }
+ if (fileName.endsWith(".wadl")) {
+ return "application/wadl+xml";
+ }
+ if (fileName.endsWith(".wsdl")) {
+ return "application/wsdl+xml";
+ }
+ if (fileName.endsWith(".xsd")) {
+ return "application/xsd+xml";
+ }
+ if (fileName.endsWith(".json")) {
+ return "application/json";
+ }
+ if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
+ return "application/html";
+ }
+ if (fileName.endsWith(".properties")) {
+ return "text/x-java-properties";
+ }
+ if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
+ return "image/jpeg";
+ }
+ if (fileName.endsWith(".png")) {
+ return "image/png";
+ }
+ if (fileName.endsWith(".gif")) {
+ return "image/gif";
+ }
+ if (fileName.endsWith(".svg")) {
+ return "image/svg+xml";
+ }
+ return "text/plain";
+ }
+
+ /**
+ * Throws an exception if the given file or directory does not exist
+ */
+ public static void assertExists(File file) {
+ if (!file.exists()) {
+ throw new IllegalArgumentException(file + " does not exist");
+ }
+ }
+
+ /**
+ * Throws an exception if the given file does not exist
+ */
+ public static void assertFileExists(File file) {
+ assertExists(file);
+ if (!file.isFile()) {
+ throw new IllegalArgumentException(file + " is not a file!");
+ }
+ }
+
+ /**
+ * Throws an exception if the given file does not exist
+ */
+ public static void assertDirectoryExists(File file) {
+ assertExists(file);
+ if (!file.isDirectory()) {
+ throw new IllegalArgumentException(file + " is not a directory!");
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Function.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Function.java"
new file mode 100755
index 0000000..a5b3408
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Function.java"
@@ -0,0 +1,11 @@
+package io.hawt.util;
+
+/**
+ * When we move to Java 8 we can switch this to be java.util.function.Function
+ */
+public interface Function {
+ /**
+ * Returns the result of applying this function to the parameter value
+ */
+ R apply(T value);
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Hosts.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Hosts.java"
new file mode 100755
index 0000000..73d9ca9
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Hosts.java"
@@ -0,0 +1,174 @@
+/**
+ * Copyright 2005-2017 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * Copied from Fabric8 v1 io.fabric8.utils.HostUtils
+ */
+public class Hosts {
+ private static final transient Logger LOG = LoggerFactory.getLogger(Hosts.class);
+
+ public static final String PREFERED_ADDRESS_PROPERTY_NAME = "preferred.network.address";
+
+ private Hosts() {
+ //Utility Class
+ }
+
+ /**
+ * Returns a {@link Set} of {@link InetAddress} per {@link NetworkInterface} as a {@link Map}.
+ *
+ * @return
+ */
+ public static Map> getNetworkInterfaceAddresses(boolean includeLoopback) {
+ //JVM returns interfaces in a non-predictable order, so to make this more predictable
+ //let's have them sort by interface name (by using a TreeMap).
+ Map> interfaceAddressMap = new TreeMap<>();
+ try {
+ Enumeration ifaces = NetworkInterface.getNetworkInterfaces();
+ while (ifaces.hasMoreElements()) {
+ NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
+ //We only care about usable interfaces.
+ if (!iface.isUp()) {
+ continue;
+ }
+ if (!includeLoopback && iface.isLoopback()) {
+ continue;
+ }
+ String name = iface.getName();
+ Enumeration ifaceAdresses = iface.getInetAddresses();
+ while (ifaceAdresses.hasMoreElements()) {
+ InetAddress ia = ifaceAdresses.nextElement();
+ if (!includeLoopback && ia.isLoopbackAddress()) {
+ continue;
+ }
+ // We want to filter out mac addresses
+ // Let's filter out docker interfaces too
+ if (!ia.getHostAddress().contains(":") && !(name != null && name.toLowerCase().contains("docker"))) {
+ Set addresses = interfaceAddressMap.get(name);
+ if (addresses == null) {
+ addresses = new LinkedHashSet<>();
+ }
+ addresses.add(ia);
+ interfaceAddressMap.put(name, addresses);
+ }
+ }
+ }
+ } catch (SocketException ex) {
+ //noop
+ }
+ return interfaceAddressMap;
+ }
+
+ /**
+ * Returns a {@link Set} of {@link InetAddress} that are non-loopback or mac.
+ * @return
+ */
+ public static Set getAddresses() {
+ Set allAddresses = new LinkedHashSet<>();
+ Map> interfaceAddressMap = getNetworkInterfaceAddresses(false);
+ for (Map.Entry> entry : interfaceAddressMap.entrySet()) {
+ Set addresses = entry.getValue();
+ if (!addresses.isEmpty()) {
+ for (InetAddress address : addresses) {
+ allAddresses.add(address);
+ }
+ }
+ }
+ return allAddresses;
+ }
+
+ /**
+ * Chooses one of the available {@link InetAddress} based on the specified preference.
+ * If the preferred address is not part of the available addresses it will be ignored.
+ *
+ * @param preferred
+ * @return
+ */
+ private static InetAddress chooseAddress(String preferred) throws UnknownHostException {
+ Set addresses = getAddresses();
+ if (preferred != null && !preferred.isEmpty()) {
+ //Favor preferred address if exists
+ try {
+ InetAddress preferredAddress = InetAddress.getByName(preferred);
+ if (addresses != null && addresses.contains(preferredAddress)) {
+ LOG.info("preferred address is " + preferredAddress.getHostAddress() + " for host " + preferredAddress.getHostName());
+ return preferredAddress;
+ }
+ } catch (UnknownHostException e) {
+ //noop
+ }
+ for (InetAddress address : addresses) {
+ if (preferred.equals(address.getHostName())) {
+ return address;
+ }
+ }
+ StringBuffer hostNameBuffer = new StringBuffer();
+ for (InetAddress address : addresses) {
+ if (hostNameBuffer.length() > 0) {
+ hostNameBuffer.append(", ");
+ }
+ hostNameBuffer.append(address.getHostName() + "/" + address.getHostAddress());
+ }
+ LOG.warn("Could not find network address for preferred '" + preferred + "' when the addresses were: " + hostNameBuffer);
+ }
+ if (addresses.contains(InetAddress.getLocalHost())) {
+ //Then if local host address is not bound to a loop-back interface, use it.
+ return InetAddress.getLocalHost();
+ } else if (addresses != null && !addresses.isEmpty()) {
+ //else return the first available addrress
+ return addresses.toArray(new InetAddress[addresses.size()])[0];
+ } else {
+ //else we are forcedt to use the localhost address.
+ return InetAddress.getLocalHost();
+ }
+ }
+
+ /**
+ * Returns the local hostname. It loops through the network interfaces and returns the first non loopback address
+ *
+ * @return
+ * @throws UnknownHostException
+ */
+ public static String getLocalHostName() throws UnknownHostException {
+ String preffered = System.getProperty(PREFERED_ADDRESS_PROPERTY_NAME);
+ return chooseAddress(preffered).getHostName();
+ }
+
+ /**
+ * Returns the local IP. It loops through the network interfaces and returns the first non loopback address
+ *
+ * @return
+ * @throws UnknownHostException
+ */
+ public static String getLocalIp() throws UnknownHostException {
+ String preffered = System.getProperty(PREFERED_ADDRESS_PROPERTY_NAME);
+ return chooseAddress(preffered).getHostAddress();
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/IOHelper.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/IOHelper.java"
new file mode 100755
index 0000000..d0333d3
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/IOHelper.java"
@@ -0,0 +1,149 @@
+package io.hawt.util;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static io.hawt.util.Closeables.closeQuietly;
+
+/**
+ * A collection of IO helpers
+ */
+public class IOHelper {
+ public static final int BUFFER_SIZE = 64 * 1024;
+
+ private static final transient Logger LOG = LoggerFactory.getLogger(IOHelper.class);
+
+ public static String readFully(File file) throws IOException {
+ return readFully(new BufferedReader(new FileReader(file)));
+ }
+
+ /**
+ * Reads the entire reader into memory as a String
+ */
+ public static String readFully(BufferedReader reader) throws IOException {
+ if (reader == null) {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder(BUFFER_SIZE);
+ char[] buf = new char[BUFFER_SIZE];
+ try {
+ int len;
+ // read until we reach then end which is the -1 marker
+ while ((len = reader.read(buf)) != -1) {
+ sb.append(buf, 0, len);
+ }
+ } finally {
+ IOHelper.close(reader, "reader", LOG);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Closes the given resource if it is available, logging any closing exceptions to the given log.
+ *
+ * @param closeable the object to close
+ * @param name the name of the resource
+ * @param log the log to use when reporting closure warnings, will use this class's own {@link Logger} if log == null
+ */
+ public static void close(Closeable closeable, String name, Logger log) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ if (log == null) {
+ // then fallback to use the own Logger
+ log = LOG;
+ }
+ if (name != null) {
+ log.warn("Cannot close: " + name + ". Reason: " + e.getMessage(), e);
+ } else {
+ log.warn("Cannot close. Reason: " + e.getMessage(), e);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Writes the text to the given file, overwriting the previous file if it existed.
+ */
+ public static void write(File file, String text) throws IOException {
+ write(file, text, false);
+ }
+
+ public static void write(File file, byte[] data) throws IOException {
+ write(file, data, false);
+ }
+
+ /**
+ * Writes the given text to the file; either in append mode or replace mode depending
+ * the append flag
+ */
+ public static void write(File file, String text, boolean append) throws IOException {
+ FileWriter writer = new FileWriter(file, append);
+ try {
+ writer.write(text);
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * Writes the given data to the file; either in append mode or replace mode depending
+ * the append flag
+ */
+ public static void write(File file, byte[] data, boolean append) throws IOException {
+ FileOutputStream stream = new FileOutputStream(file, append);
+ try {
+ stream.write(data);
+ } finally {
+ stream.close();
+ }
+ }
+
+ public static int copy(final Reader input, final Writer output) throws IOException {
+ return copy(input, output, BUFFER_SIZE);
+ }
+
+ public static int copy(final Reader input, final Writer output, int bufferSize) throws IOException {
+ final char[] buffer = new char[bufferSize];
+ int n = input.read(buffer);
+ int total = 0;
+ while (-1 != n) {
+ output.write(buffer, 0, n);
+ total += n;
+ n = input.read(buffer);
+ }
+ output.flush();
+ return total;
+ }
+
+ public static void copy(InputStream is, OutputStream os) throws IOException {
+ try {
+ byte[] b = new byte[64 * 1024];
+ int l = is.read(b);
+ while (l >= 0) {
+ os.write(b, 0, l);
+ l = is.read(b);
+ }
+ } finally {
+ closeQuietly(os);
+ }
+ }
+
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/MBeanSupport.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/MBeanSupport.java"
new file mode 100755
index 0000000..d1037d8
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/MBeanSupport.java"
@@ -0,0 +1,80 @@
+package io.hawt.util;
+
+import java.lang.management.ManagementFactory;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A helpful base class for MBeans
+ */
+public abstract class MBeanSupport {
+ private static final transient Logger LOG = LoggerFactory.getLogger(MBeanSupport.class);
+
+ private ObjectName objectName;
+ private ObjectInstance objectInstance;
+ private MBeanServer mBeanServer;
+ private boolean registered;
+
+ public void init() throws Exception {
+ // lets check if we have a config directory if not lets create one...
+ // now lets expose the mbean...
+ if (objectName == null) {
+ objectName = new ObjectName(getDefaultObjectName());
+ }
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ if (!registered && !mBeanServer.isRegistered(objectName)) {
+ try {
+ objectInstance = mBeanServer.registerMBean(this, objectName);
+ } catch (InstanceAlreadyExistsException iaee) {
+ // Try to remove and re-register
+ LOG.warn("This mbean is already registered " + objectName + ". There must be multiple deployment units with this mbean inside.");
+/*
+ mBeanServer.unregisterMBean(objectName);
+ mBeanServer.registerMBean(this, objectName);
+*/
+ }
+ registered = true;
+ }
+ }
+
+ public void destroy() throws Exception {
+ if (registered && objectName != null && mBeanServer != null) {
+ registered = false;
+ try {
+ // favor object name from object instance as some containers may use special naming
+ if (objectInstance != null && objectInstance.getObjectName() != null) {
+ mBeanServer.unregisterMBean(objectInstance.getObjectName());
+ } else {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ } catch (Exception e) {
+ LOG.debug("Error unregistering mbean " + objectName + ". This exception is ignored.", e);
+ }
+ }
+ }
+
+ public MBeanServer getMBeanServer() {
+ return mBeanServer;
+ }
+
+ public void setMBeanServer(MBeanServer mBeanServer) {
+ this.mBeanServer = mBeanServer;
+ }
+
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+ public void setObjectName(ObjectName objectName) {
+ this.objectName = objectName;
+ }
+
+ protected abstract String getDefaultObjectName();
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Objects.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Objects.java"
new file mode 100755
index 0000000..fddb4b4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Objects.java"
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Some helper methods - though could be replaced by JDK 1.7 code now in java.util.Objects
+ * whenever we are happy to ignore JDK 1.6
+ */
+public class Objects {
+ private static final transient Logger LOG = LoggerFactory.getLogger(Objects.class);
+
+ public static boolean equals(Object a, Object b) {
+ if (a == b) {
+ return true;
+ } else {
+ return a != null && b != null && a.equals(b);
+ }
+ }
+
+ public static int compare(Comparable a, Comparable b) {
+ if (a == b) {
+ return 0;
+ }
+ if (a == null) {
+ return -1;
+ }
+ if (b == null) {
+ return 1;
+ }
+ return a.compareTo(b);
+ }
+
+
+ /**
+ * Returns the version of the given class's package or the group and artifact of the jar
+ */
+ public static String getVersion(Class> aClass, String groupId, String artifactId) {
+ String version = null;
+ // lets try find the maven property - as the Java API rarely works :)
+ InputStream is = null;
+ String fileName = "/META-INF/maven/" +
+ groupId + "/" + artifactId +
+ "/pom.properties";
+ // try to load from maven properties first
+ try {
+ Properties p = new Properties();
+ is = aClass.getResourceAsStream(fileName);
+ if (is != null) {
+ p.load(is);
+ version = p.getProperty("version", "");
+ }
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ if (is != null) {
+ IOHelper.close(is, fileName, LOG);
+ }
+ }
+ if (version == null) {
+ Package aPackage = aClass.getPackage();
+ if (aPackage != null) {
+ version = aPackage.getImplementationVersion();
+ if (Strings.isBlank(version)) {
+ version = aPackage.getSpecificationVersion();
+ }
+ }
+ }
+ if (version == null) {
+ Enumeration resources = null;
+ try {
+ resources = aClass.getClassLoader().getResources("META-INF/MANIFEST.MF");
+ } catch (IOException e) {
+ // ignore
+ }
+ if (resources != null) {
+ String expectedBundleName = groupId + "." + artifactId;
+ while (resources.hasMoreElements()) {
+ try {
+ Manifest manifest = new Manifest(resources.nextElement().openStream());
+ Attributes attributes = manifest.getMainAttributes();
+ String bundleName = attributes.getValue("Bundle-SymbolicName");
+ if (Objects.equals(expectedBundleName, bundleName)) {
+ version = attributes.getValue("Implementation-Version");
+ if (Strings.isNotBlank(version)) break;
+ }
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ return version;
+ }
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Predicate.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Predicate.java"
new file mode 100755
index 0000000..fb7d1a1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Predicate.java"
@@ -0,0 +1,25 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util;
+
+/**
+ * Evaluates the predicate on the given value
+ */
+public interface Predicate {
+ boolean evaluate(T value);
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/ReflectionHelper.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/ReflectionHelper.java"
new file mode 100755
index 0000000..e7b6212
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/ReflectionHelper.java"
@@ -0,0 +1,92 @@
+package io.hawt.util;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public final class ReflectionHelper {
+
+ /**
+ * A helper method to create a new instance of a type using the default
+ * constructor arguments.
+ */
+ public static T newInstance(Class type) {
+ try {
+ return type.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * A helper method to invoke a method via reflection and wrap any exceptions
+ * as {@link RuntimeException} instances
+ *
+ * @param method the method to invoke
+ * @param instance the object instance (or null for static methods)
+ * @param parameters the parameters to the method
+ * @return the result of the method invocation
+ */
+ public static Object invokeMethod(Method method, Object instance, Object... parameters) {
+ if (method == null) {
+ return null;
+ }
+ try {
+ return method.invoke(instance, parameters);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ }
+ }
+
+ /**
+ * Returns true if the given type has a method with the given annotation
+ */
+ public static boolean hasMethodWithAnnotation(Class> type,
+ Class extends Annotation> annotationType,
+ boolean checkMetaAnnotations) {
+ try {
+ do {
+ Method[] methods = type.getDeclaredMethods();
+ for (Method method : methods) {
+ if (hasAnnotation(method, annotationType, checkMetaAnnotations)) {
+ return true;
+ }
+ }
+ type = type.getSuperclass();
+ } while (type != null);
+ } catch (Throwable e) {
+ // ignore a class loading issue
+ }
+ return false;
+ }
+
+ /**
+ * Checks if a Class or Method are annotated with the given annotation
+ *
+ * @param elem the Class or Method to reflect on
+ * @param annotationType the annotation type
+ * @param checkMetaAnnotations check for meta annotations
+ * @return true if annotations is present
+ */
+ public static boolean hasAnnotation(AnnotatedElement elem, Class extends Annotation> annotationType,
+ boolean checkMetaAnnotations) {
+ if (elem.isAnnotationPresent(annotationType)) {
+ return true;
+ }
+ if (checkMetaAnnotations) {
+ for (Annotation a : elem.getAnnotations()) {
+ for (Annotation meta : a.annotationType().getAnnotations()) {
+ if (meta.annotationType().getName().equals(annotationType.getName())) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Strings.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Strings.java"
new file mode 100755
index 0000000..832fb9f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Strings.java"
@@ -0,0 +1,135 @@
+package io.hawt.util;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * String utility.
+ */
+public class Strings {
+
+ public static String trimString(String value, int max) {
+ if (value == null) {
+ return "";
+ }
+ if (value.length() <= max) {
+ return value;
+ }
+ return value.substring(0, max - 3) + "...";
+ }
+
+ public static boolean isBlank(String text) {
+ return text == null || text.trim().length() == 0;
+ }
+
+ public static boolean isNotBlank(String text) {
+ return text != null && text.trim().length() > 0;
+ }
+
+ /**
+ * Strip out any annoying to deal with characters from a string when used as a
+ * file or directory name
+ *
+ * @param name
+ * @return
+ */
+ public static String sanitize(String name) {
+ if (isBlank(name)) {
+ return name;
+ }
+ return name.replaceAll("[^0-9a-zA-Z\\+\\.\\(\\)_\\-]", "");
+ }
+
+ /**
+ * Also remove any dots in the directory name
+ *
+ * @param name
+ * @return
+ */
+ public static String sanitizeDirectory(String name) {
+ if (isBlank(name)) {
+ return name;
+ }
+ return sanitize(name).replace(".", "");
+ }
+
+ public static List split(String text, String delimiter) {
+ if (text == null || delimiter == null) {
+ throw new IllegalArgumentException(
+ "Both 'text' and 'delimiter' should not be null.");
+ }
+ return Arrays.stream(text.split(delimiter)).map(s -> s.trim())
+ .filter(s -> isNotBlank(s)).collect(Collectors.toList());
+ }
+
+ /**
+ * Normalizes a path. If the path contains a single '/' character it is returned
+ * unchanged, otherwise the path is:
+ *
+ * stripped from all multiple consecutive occurrences of '/' characters
+ * stripped from trailing '/' character(s)
+ *
+ *
+ * @param path
+ * path to normalize
+ * @return normalized path
+ */
+ public static String cleanPath(final String path) {
+ final String result = path.replaceAll("//+", "/");
+ return result.length() == 1 && result.charAt(0) == '/' ? result
+ : result.replaceAll("/+$", "");
+ }
+
+ /**
+ * Creates a web context path from components. Concatenates all path components
+ * using '/' character as delimiter and the result is then:
+ *
+ * prefixed with '/' character
+ * stripped from all multiple consecutive occurrences of '/' characters
+ * stripped from trailing '/' character(s)
+ *
+ *
+ * @param components
+ * web context path components
+ * @return empty string or string which starts with a "/" character but does not
+ * end with a "/" character
+ */
+ public static String webContextPath(final String first, final String... more) {
+ if (more.length == 0 && (first == null || first.isEmpty())) {
+ return "";
+ }
+
+ final StringBuilder b = new StringBuilder();
+ if (first != null) {
+ if (!first.startsWith("/")) {
+ b.append('/');
+ }
+ b.append(first);
+ }
+
+ for (final String s : more) {
+ if (s != null && !s.isEmpty()) {
+ b.append('/');
+ b.append(s);
+ }
+ }
+
+ final String cleanedPath = cleanPath(b.toString());
+ return cleanedPath.length() == 1 ? "" : cleanedPath;
+ }
+
+ public static String strip(String text, String chars) {
+ if (text == null || chars == null) {
+ throw new IllegalArgumentException("Both 'text' and 'chars' should not be null.");
+ }
+ String answer = text;
+ if (answer.startsWith(chars)) {
+ answer = answer.substring(chars.length());
+ }
+ if (answer.endsWith(chars)) {
+ answer = answer.substring(0, answer.length() - chars.length());
+ }
+ return answer;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/XmlHelper.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/XmlHelper.java"
new file mode 100755
index 0000000..5b6c8f4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/XmlHelper.java"
@@ -0,0 +1,53 @@
+package io.hawt.util;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Set;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * A helper method to get the namespaces on an XML file
+ */
+public class XmlHelper {
+ private static SAXParserFactory factory;
+
+ /**
+ * Returns the namespace URIs found in the given XML file
+ */
+ public static Set getNamespaces(File file) throws ParserConfigurationException, SAXException, IOException {
+ return getNamespaces(new InputSource(new FileReader(file)));
+ }
+
+ /**
+ * Returns the namespace URIs found in the given XML file
+ */
+ public static Set getNamespaces(InputSource source) throws ParserConfigurationException, SAXException, IOException {
+ XmlNamespaceFinder finder = createNamespaceFinder();
+ Set answer = finder.parseContents(source);
+ if (factory == null) {
+ factory = finder.getFactory();
+ }
+ return answer;
+ }
+
+ public static SAXParserFactory getFactory() {
+ return factory;
+ }
+
+ public static void setFactory(SAXParserFactory factory) {
+ XmlHelper.factory = factory;
+ }
+
+ protected static XmlNamespaceFinder createNamespaceFinder() {
+ XmlNamespaceFinder finder = new XmlNamespaceFinder();
+ if (factory != null) {
+ finder.setFactory(factory);
+ }
+ return finder;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/XmlNamespaceFinder.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/XmlNamespaceFinder.java"
new file mode 100755
index 0000000..db11abc
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/XmlNamespaceFinder.java"
@@ -0,0 +1,83 @@
+package io.hawt.util;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+public class XmlNamespaceFinder extends DefaultHandler {
+
+ private Set namespaces = new HashSet();
+ private boolean namespaceFound = false;
+ private SAXParserFactory factory;
+
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ super.startElement(uri, localName, qName, attributes);
+
+ if (!namespaceFound) {
+ if (uri != null && uri.length() > 0) {
+ namespaces.add(uri);
+ }
+ }
+ }
+
+ public Set getNamespaces() {
+ return namespaces;
+ }
+
+ public SAXParserFactory getFactory() {
+ return factory;
+ }
+
+ public void setFactory(SAXParserFactory factory) {
+ this.factory = factory;
+ }
+
+ public Set parseContents(InputSource contents) throws IOException, ParserConfigurationException, SAXException {
+ namespaces.clear();
+ // Parse the file into we have what we need (or an error occurs).
+ if (factory == null) {
+ factory = SAXParserFactory.newInstance();
+ }
+ if (factory != null) {
+ SAXParser parser = createParser(factory);
+ // to support external entities specified as relative URIs (see bug 63298)
+ contents.setSystemId("/"); //$NON-NLS-1$
+ parser.parse(contents, this);
+ }
+ return namespaces;
+ }
+
+ protected final SAXParser createParser(SAXParserFactory parserFactory)
+ throws ParserConfigurationException, SAXException {
+ parserFactory.setNamespaceAware(true);
+ final SAXParser parser = parserFactory.newSAXParser();
+ final XMLReader reader = parser.getXMLReader();
+ //reader.setProperty("http://xml.org/sax/properties/lexical-handler", this); //$NON-NLS-1$
+ // disable DTD validation (bug 63625)
+ try {
+ // be sure validation is "off" or the feature to ignore DTD's will not apply
+ reader.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$
+ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$
+ } catch (SAXNotRecognizedException e) {
+ // not a big deal if the parser does not recognize the features
+ } catch (SAXNotSupportedException e) {
+ // not a big deal if the parser does not support the features
+ }
+ return parser;
+ }
+
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Zips.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Zips.java"
new file mode 100755
index 0000000..cb7dc15
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/Zips.java"
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.slf4j.Logger;
+
+import static io.hawt.util.Closeables.closeQuietly;
+import static io.hawt.util.IOHelper.copy;
+
+/**
+ */
+public class Zips {
+ /**
+ * Creates a zip fie from the given source directory and output zip file name
+ */
+ public static void createZipFile(Logger log, File sourceDir, File outputZipFile) throws IOException {
+ FileFilter filter = null;
+ createZipFile(log, sourceDir, outputZipFile, filter);
+ }
+
+ public static void createZipFile(Logger log, File sourceDir, File outputZipFile, FileFilter filter) throws IOException {
+ outputZipFile.getParentFile().mkdirs();
+ OutputStream os = new FileOutputStream(outputZipFile);
+ ZipOutputStream zos = new ZipOutputStream(os);
+ try {
+ //zos.setLevel(Deflater.DEFAULT_COMPRESSION);
+ //zos.setLevel(Deflater.NO_COMPRESSION);
+ String path = "";
+ zipDirectory(log, sourceDir, zos, path, filter);
+ } finally {
+ closeQuietly(zos);
+ }
+ }
+
+ /**
+ * Zips the directory recursively into the ZIP stream given the starting path and optional filter
+ */
+ public static void zipDirectory(Logger log, File directory, ZipOutputStream zos, String path, FileFilter filter) throws IOException {
+ // get a listing of the directory content
+ File[] dirList = directory.listFiles();
+ byte[] readBuffer = new byte[8192];
+ int bytesIn = 0;
+ // loop through dirList, and zip the files
+ if (dirList != null) {
+ for (File f : dirList) {
+ if (f.isDirectory()) {
+ String prefix = path + f.getName() + "/";
+ if (matches(filter, f)) {
+ zos.putNextEntry(new ZipEntry(prefix));
+ zipDirectory(log, f, zos, prefix, filter);
+ }
+ } else {
+ String entry = path + f.getName();
+ if (matches(filter, f)) {
+ FileInputStream fis = new FileInputStream(f);
+ try {
+ ZipEntry anEntry = new ZipEntry(entry);
+ zos.putNextEntry(anEntry);
+ bytesIn = fis.read(readBuffer);
+ while (bytesIn != -1) {
+ zos.write(readBuffer, 0, bytesIn);
+ bytesIn = fis.read(readBuffer);
+ }
+ } finally {
+ fis.close();
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("zipping file " + entry);
+ }
+ }
+ }
+ zos.closeEntry();
+ }
+ }
+ }
+
+ protected static boolean matches(FileFilter filter, File f) {
+ return filter == null || filter.accept(f);
+ }
+
+ /**
+ * Unzips the given input stream of a ZIP to the given directory
+ */
+ public static void unzip(InputStream in, File toDir) throws IOException {
+ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(in));
+ try {
+ ZipEntry entry = zis.getNextEntry();
+ while (entry != null) {
+ if (!entry.isDirectory()) {
+ String entryName = entry.getName();
+ File toFile = new File(toDir, entryName);
+ toFile.getParentFile().mkdirs();
+ OutputStream os = new FileOutputStream(toFile);
+ try {
+ try {
+ copy(zis, os);
+ } finally {
+ zis.closeEntry();
+ }
+ } finally {
+ closeQuietly(os);
+ }
+ }
+ entry = zis.getNextEntry();
+ }
+ } finally {
+ closeQuietly(zis);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/ClassLoaderProvider.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/ClassLoaderProvider.java"
new file mode 100755
index 0000000..fb362d1
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/ClassLoaderProvider.java"
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util.introspect;
+
+/**
+ * Represents a provider of a {@link ClassLoader}
+ */
+public interface ClassLoaderProvider {
+
+ /**
+ * Returns the ClassLoader or null if one is not available
+ */
+ ClassLoader getClassLoader();
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/ClassLoaderProviders.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/ClassLoaderProviders.java"
new file mode 100755
index 0000000..1e264ff
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/ClassLoaderProviders.java"
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util.introspect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class for creating instances of {@link ClassLoaderProvider}
+ */
+public class ClassLoaderProviders {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ClassLoaderProviders.class);
+
+ public static ClassLoaderProvider createConstantProvider(final ClassLoader classLoader) {
+ return new ClassLoaderProvider() {
+ @Override
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ @Override
+ public String toString() {
+ return "ClassLoaderProvider(" + classLoader + ")";
+ }
+ };
+ }
+
+ public static ClassLoaderProvider createReflectionProvider(final Object instance, final Method method) {
+ return new ClassLoaderProvider() {
+ @Override
+ public ClassLoader getClassLoader() {
+ Object value = null;
+ try {
+ value = method.invoke(instance);
+ } catch (InvocationTargetException te) {
+ Throwable e = te.getTargetException();
+ LOG.warn("Failed to invoke " + method + " on " + instance + ". " + e, e);
+ } catch (Exception e) {
+ LOG.warn("Failed to invoke " + method + " on " + instance + ". " + e, e);
+ }
+ if (value != null) {
+ if (value instanceof ClassLoader) {
+ return (ClassLoader) value;
+ } else {
+ LOG.warn("Value returned from " + method + " on " + instance + " is not a ClassLoader: " + value);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "ReflectionClassLoaderProvider(" + instance + ", " + method + ")";
+ }
+ };
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/CacheValue.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/CacheValue.java"
new file mode 100755
index 0000000..8fdcd07
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/CacheValue.java"
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util.introspect.support;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ */
+public class CacheValue {
+ private SortedSet classNames = new TreeSet();
+
+ public SortedSet getClassNames() {
+ return classNames;
+ }
+
+ public void setClassNames(SortedSet classNames) {
+ this.classNames = classNames;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/ClassResource.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/ClassResource.java"
new file mode 100755
index 0000000..f904a98
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/ClassResource.java"
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util.introspect.support;
+
+import java.net.URL;
+
+/**
+ */
+public class ClassResource {
+ final String packageName;
+ final URL resource;
+
+ public ClassResource(String packageName, URL resource) {
+ this.packageName = packageName;
+ this.resource = resource;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public URL getResource() {
+ return resource;
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/ClassScanner.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/ClassScanner.java"
new file mode 100755
index 0000000..8374b16
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/ClassScanner.java"
@@ -0,0 +1,560 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util.introspect.support;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import io.hawt.util.Predicate;
+import io.hawt.util.ReflectionHelper;
+import io.hawt.util.Strings;
+import io.hawt.util.introspect.ClassLoaderProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A helper class to scan classes on the classpath
+ */
+public class ClassScanner {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ClassScanner.class);
+
+ // lets skip some classes which can cause ugly WARN logging when doing package scanning
+ private static final String[] SKIP_CLASSES = new String[]{"org.apache.log4j.net.ZeroConfSupport"};
+
+ private final ClassLoader[] classLoaders;
+
+ private WeakHashMap cache = new WeakHashMap();
+ private WeakHashMap packageCache = new WeakHashMap();
+ private Map classLoaderProviderMap = new HashMap();
+ private Set ignorePackages = new HashSet(Arrays.asList("sun.reflect.misc"));
+
+ public static ClassScanner newInstance() {
+ return new ClassScanner(Thread.currentThread().getContextClassLoader(), ClassScanner.class.getClassLoader());
+ }
+
+ public ClassScanner(ClassLoader... classLoaders) {
+ this.classLoaders = classLoaders;
+ }
+
+ public void clearCache() {
+ cache.clear();
+ packageCache.clear();
+ classLoaderProviderMap.clear();
+ }
+
+ /**
+ * Registers a named class loader provider or removes it if the classLoaderProvider is null
+ */
+ public void setClassLoaderProvider(String id, ClassLoaderProvider classLoaderProvider) {
+ if (classLoaderProvider != null) {
+ classLoaderProviderMap.put(id, classLoaderProvider);
+ } else {
+ classLoaderProviderMap.remove(id);
+ }
+ }
+
+ /**
+ * Searches for the available class names given the text search
+ *
+ * @return all the class names found on the current classpath using the given text search filter
+ */
+ public SortedSet findClassNames(String search, Integer limit) {
+ Map packageMap = Packages.getPackageMap(getClassLoaders(), ignorePackages);
+ return findClassNamesInPackages(search, limit, packageMap);
+ }
+
+ public SortedSet findClassNamesMethodsAnnotatedWith(String annotationClassName) {
+ Map packageMap = Packages.getPackageMap(getClassLoaders(), ignorePackages);
+ return findClassNamesMethodsAnnotatedWith(annotationClassName, null, packageMap);
+ }
+
+ public SortedSet findClassNamesInDirectoryWithMethodAnnotatedWith(File dir, String annotationClassName) {
+ SortedSet answer = new TreeSet();
+ final Class extends Annotation> annotationClass = optionallyFindAnnotationClass(annotationClassName);
+ if (annotationClass != null && dir.exists()) {
+ addClassNamesInDirectoryWithMethodsAnnotatedWith(answer, dir, annotationClass, "");
+ }
+ return answer;
+ }
+
+ protected void addClassNamesInDirectoryWithMethodsAnnotatedWith(SortedSet answer, File dir,
+ Class extends Annotation> annotationClass, String packageName) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ addClassNamesInDirectoryWithMethodsAnnotatedWith(answer, file, annotationClass, packageName + file.getName() + ".");
+ } else if (file.isFile()) {
+ String name = file.getName();
+ if (name.endsWith(".class")) {
+ String className = packageName + (name.substring(0, name.length() - 6).replace('$', '.'));
+ Class> aClass = optionallyFindClass(className);
+ if (aClass != null && ReflectionHelper.hasMethodWithAnnotation(aClass, annotationClass, true)) {
+ answer.add(className);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ protected Class extends Annotation> optionallyFindAnnotationClass(String annotationClassName) {
+ final Class extends Annotation> annotationClass = optionallyFindClass(annotationClassName).asSubclass(Annotation.class);
+ if (annotationClass != null && Annotation.class.isAssignableFrom(annotationClass)) {
+ return annotationClass;
+ }
+ return null;
+ }
+
+ public SortedSet findClassNamesMethodsAnnotatedWith(String annotationClassName, Integer limit, Map packages) {
+ final Class extends Annotation> annotationClass = optionallyFindAnnotationClass(annotationClassName);
+ if (annotationClass != null) {
+ Predicate filter = new Predicate() {
+ @Override
+ public boolean evaluate(String className) {
+ Class> aClass = optionallyFindClass(className);
+ if (aClass != null) {
+ return ReflectionHelper.hasMethodWithAnnotation(aClass, annotationClass, true);
+ }
+ return false;
+ }
+ };
+ return findClassNames(packages, filter, limit);
+ }
+ return new TreeSet();
+ }
+
+
+ public SortedSet findClassNamesInPackages(final String search, Integer limit, Map packages) {
+ Predicate filter = new Predicate() {
+ @Override
+ public boolean evaluate(String aClass) {
+ return classNameMatches(aClass, search);
+ }
+ };
+ return findClassNames(packages, filter, limit);
+ }
+
+ protected SortedSet findClassNames(Map packages, Predicate filter, Integer limit) {
+ SortedSet answer = new TreeSet();
+ SortedSet classes = new TreeSet();
+
+ Set> entries = packages.entrySet();
+ for (Map.Entry entry : entries) {
+ Package aPackage = entry.getKey();
+ ClassLoader[] classLoaders = entry.getValue();
+ CacheValue cacheValue = packageCache.get(aPackage);
+ if (cacheValue == null) {
+ cacheValue = createPackageCacheValue(aPackage, classLoaders);
+ packageCache.put(aPackage, cacheValue);
+ }
+ classes.addAll(cacheValue.getClassNames());
+ }
+
+/*
+ for (Map.Entry entry : entries) {
+ String key = entry.getKey();
+ ClassResource classResource = entry.getValue();
+ CacheValue cacheValue = cache.get(key);
+ if (cacheValue == null) {
+ cacheValue = createCacheValue(key, classResource);
+ cache.put(key, cacheValue);
+ }
+ classes.addAll(cacheValue.getClassNames());
+ //addClassesForPackage(classResource, search, limit, classes);
+ }
+*/
+
+ if (withinLimit(limit, answer)) {
+ for (String aClass : classes) {
+ if (filter.evaluate(aClass)) {
+ answer.add(aClass);
+ if (!withinLimit(limit, answer)) {
+ break;
+ }
+ }
+ }
+ }
+ return answer;
+ }
+
+
+ /**
+ * Returns all the classes found in a sorted map
+ */
+ public SortedMap> getAllClassesMap() {
+ Package[] packages = Package.getPackages();
+ return getClassesMap(packages);
+ }
+
+ /**
+ * Returns all the classes found in a sorted map for the given list of packages
+ */
+ public SortedMap> getClassesMap(Package... packages) {
+ SortedMap> answer = new TreeMap>();
+ Map urlSet = new HashMap();
+ for (Package aPackage : packages) {
+ addPackageResources(aPackage, urlSet, classLoaders);
+ }
+ for (ClassResource classResource : urlSet.values()) {
+ Set> classes = getClassesForPackage(classResource, null, null);
+ for (Class> aClass : classes) {
+ answer.put(aClass.getName(), aClass);
+ }
+ }
+ return answer;
+ }
+
+ public Set> getClassesForPackage(ClassResource classResource, String filter, Integer limit) {
+ Set> classes = new HashSet>();
+ addClassesForPackage(classResource, filter, limit, classes);
+ return classes;
+ }
+
+ /**
+ * Finds a class from its name
+ */
+ public Class> findClass(String className) throws ClassNotFoundException {
+ for (String skip : SKIP_CLASSES) {
+ if (skip.equals(className)) {
+ return null;
+ }
+ }
+
+ for (ClassLoader classLoader : getClassLoaders()) {
+ try {
+ return classLoader.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ }
+ return Class.forName(className);
+ }
+
+ /**
+ * Returns the given class or null if it cannot be loaded
+ */
+ public Class> optionallyFindClass(String className) {
+ try {
+ return findClass(className);
+ } catch (Throwable e) {
+ // ignore
+ return null;
+ }
+ }
+
+ /**
+ * Tries to find as many of the class names on the class loaders as possible and return them
+ */
+ public List> optionallyFindClasses(Iterable classNames) {
+ List> answer = new ArrayList>();
+ for (String className : classNames) {
+ Class> aClass = optionallyFindClass(className);
+ if (aClass != null) {
+ answer.add(aClass);
+ }
+ }
+ return answer;
+ }
+
+
+ public Set getIgnorePackages() {
+ return ignorePackages;
+ }
+
+ public void setIgnorePackages(Set ignorePackages) {
+ this.ignorePackages = ignorePackages;
+ }
+
+ // Implementation methods
+ //-------------------------------------------------------------------------
+ protected void addPackageResources(Package aPackage, Map urlSet, ClassLoader[] classLoaders) {
+ String packageName = aPackage.getName();
+ String relativePath = getPackageRelativePath(packageName);
+ List resources = getResources(relativePath, classLoaders);
+ for (URL resource : resources) {
+ String key = getJavaResourceKey(resource);
+ urlSet.put(key, new ClassResource(packageName, resource));
+ }
+ }
+
+
+ private CacheValue createPackageCacheValue(Package aPackage, ClassLoader[] classLoaders) {
+ Map urlSet = new HashMap();
+ addPackageResources(aPackage, urlSet, classLoaders);
+
+ CacheValue answer = new CacheValue();
+ SortedSet classNames = answer.getClassNames();
+ Set> entries = urlSet.entrySet();
+ for (Map.Entry entry : entries) {
+ String key = entry.getKey();
+ ClassResource classResource = entry.getValue();
+ CacheValue cacheValue = cache.get(key);
+ if (cacheValue == null) {
+ cacheValue = createCacheValue(key, classResource);
+ cache.put(key, cacheValue);
+ }
+ classNames.addAll(cacheValue.getClassNames());
+ }
+ return answer;
+ }
+
+ protected CacheValue createCacheValue(String key, ClassResource classResource) {
+ CacheValue answer = new CacheValue();
+ SortedSet classNames = answer.getClassNames();
+ String packageName = classResource.getPackageName();
+ URL resource = classResource.getResource();
+ if (resource != null) {
+ String resourceText = resource.toString();
+ LOG.debug("Searching resource " + resource);
+ if (resourceText.startsWith("jar:")) {
+ processJarClassNames(classResource, classNames);
+ } else {
+ processDirectoryClassNames(new File(resource.getPath()), packageName, classNames);
+ }
+ }
+ return answer;
+ }
+
+ protected void processDirectoryClassNames(File directory, String packageName, Set classes) {
+ String[] fileNames = directory.list();
+ if (fileNames != null) {
+ for (String fileName : fileNames) {
+ String packagePrefix = Strings.isNotBlank(packageName) ? packageName + '.' : packageName;
+ if (fileName.endsWith(".class")) {
+ String className = packagePrefix + fileName.substring(0, fileName.length() - 6);
+ classes.add(className);
+ }
+ File subdir = new File(directory, fileName);
+ if (subdir.isDirectory()) {
+ processDirectoryClassNames(subdir, packagePrefix + fileName, classes);
+ }
+ }
+ }
+ }
+
+ protected void processJarClassNames(ClassResource classResource, Set classes) {
+ URL resource = classResource.getResource();
+ String packageName = classResource.getPackageName();
+ String relativePath = getPackageRelativePath(packageName);
+ String jarPath = getJarPath(resource);
+ JarFile jarFile;
+ try {
+ jarFile = new JarFile(jarPath);
+ } catch (IOException e) {
+ LOG.debug("IOException reading JAR '" + jarPath + ". Reason: " + e, e);
+ return;
+ }
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String entryName = entry.getName();
+ if (entryName.endsWith(".class") && entryName.startsWith(relativePath) && entryName.length() > (relativePath.length() + 1)) {
+ String className = entryName.replace('/', '.').replace('\\', '.').replace(".class", "");
+ classes.add(className);
+ }
+ }
+
+ // let's not leak resources
+ try {
+ jarFile.close();
+ } catch (IOException e) {
+ LOG.debug("IOException closing JAR '" + jarPath + "'. Reason: " + e, e);
+ }
+ }
+
+
+ protected void addClassesForPackage(ClassResource classResource, String filter, Integer limit, Set> classes) {
+ String packageName = classResource.getPackageName();
+ URL resource = classResource.getResource();
+ if (resource != null && withinLimit(limit, classes)) {
+ String resourceText = resource.toString();
+ LOG.debug("Searching resource " + resource);
+ if (resourceText.startsWith("jar:")) {
+ processJar(classResource, classes, filter, limit);
+ } else {
+ processDirectory(new File(resource.getPath()), packageName, classes, filter, limit);
+ }
+ }
+ }
+
+ protected void processDirectory(File directory, String packageName, Set> classes, String filter, Integer limit) {
+ String[] fileNames = directory.list();
+ if (fileNames != null) {
+ for (String fileName : fileNames) {
+ if (!withinLimit(limit, classes)) {
+ return;
+ }
+ String className = null;
+ String packagePrefix = Strings.isNotBlank(packageName) ? packageName + '.' : packageName;
+ if (fileName.endsWith(".class")) {
+ className = packagePrefix + fileName.substring(0, fileName.length() - 6);
+ }
+ Class> aClass = tryFindClass(className, filter);
+ if (aClass != null) {
+ classes.add(aClass);
+ }
+ File subdir = new File(directory, fileName);
+ if (subdir.isDirectory()) {
+ processDirectory(subdir, packagePrefix + fileName, classes, filter, limit);
+ }
+ }
+ }
+ }
+
+ protected void processJar(ClassResource classResource, Set> classes, String filter, Integer limit) {
+ URL resource = classResource.getResource();
+ String packageName = classResource.getPackageName();
+ String relativePath = getPackageRelativePath(packageName);
+ String jarPath = getJarPath(resource);
+ JarFile jarFile;
+ try {
+ jarFile = new JarFile(jarPath);
+ } catch (IOException e) {
+ LOG.debug("IOException reading JAR '" + jarPath + ". Reason: " + e, e);
+ return;
+ }
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements() && withinLimit(limit, classes)) {
+ JarEntry entry = entries.nextElement();
+ String entryName = entry.getName();
+ String className = null;
+ if (entryName.endsWith(".class") && entryName.startsWith(relativePath) && entryName.length() > (relativePath.length() + 1)) {
+ className = entryName.replace('/', '.').replace('\\', '.').replace(".class", "");
+ }
+ Class> aClass = tryFindClass(className, filter);
+ if (aClass != null) {
+ classes.add(aClass);
+ }
+ }
+
+ // let's not leak resources
+ try {
+ jarFile.close();
+ } catch (IOException e) {
+ LOG.debug("IOException closing JAR '" + jarPath + "'. Reason: " + e, e);
+ }
+ }
+
+ protected String getJavaResourceKey(URL resource) {
+ String resourceText = resource.toString();
+ if (resourceText.startsWith("jar:")) {
+ return "jar:" + getJarPath(resource);
+ } else {
+ return resource.getPath();
+ }
+ }
+
+ private String getJarPath(URL resource) {
+ String resourcePath = resource.getPath();
+ return resourcePath.replaceFirst("[.]jar[!].*", ".jar").replaceFirst("file:", "");
+ }
+
+ protected Class> tryFindClass(String className, String filter) {
+ Class> aClass = null;
+ if (Strings.isNotBlank(className) && classNameMatches(className, filter)) {
+ try {
+ aClass = findClass(className);
+ } catch (Throwable e) {
+ LOG.debug("Could not load class " + className + ". " + e, e);
+ }
+ }
+ return aClass;
+ }
+
+ protected List getResources(String relPath, ClassLoader... classLoaders) {
+ List answer = new ArrayList();
+ for (ClassLoader classLoader : classLoaders) {
+ try {
+ Enumeration resources = classLoader.getResources(relPath);
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ if (url != null) {
+ answer.add(url);
+ }
+ }
+ } catch (IOException e) {
+ LOG.warn("Failed to load resources for path " + relPath + " from class loader " + classLoader + ". Reason: " + e, e);
+ }
+ // Lets add all the parent class loaders...
+ if (classLoader instanceof URLClassLoader) {
+ URLClassLoader loader = (URLClassLoader) classLoader;
+ answer.addAll(Arrays.asList(loader.getURLs()));
+ }
+ }
+ return answer;
+ }
+
+ /**
+ * Returns true if the given class name matches the filter search
+ */
+ protected boolean classNameMatches(String className, String search) {
+ return className.contains(search);
+ }
+
+ protected String getPackageRelativePath(String packageName) {
+ return packageName.replace('.', '/');
+ }
+
+ /**
+ * Returns true if we are within the limit value for the number of results in the collection
+ */
+ protected boolean withinLimit(Integer limit, Collection> collection) {
+ if (limit == null) {
+ return true;
+ } else {
+ int value = limit.intValue();
+ return value <= 0 || value > collection.size();
+ }
+ }
+
+ public List getClassLoaders() {
+ List answer = new ArrayList();
+ answer.addAll(Arrays.asList(classLoaders));
+
+ Collection classLoaderProviders = classLoaderProviderMap.values();
+ for (ClassLoaderProvider classLoaderProvider : classLoaderProviders) {
+ ClassLoader classLoader = classLoaderProvider.getClassLoader();
+ if (classLoader != null) {
+ answer.add(classLoader);
+ }
+ }
+ return answer;
+ }
+
+}
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/Packages.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/Packages.java"
new file mode 100755
index 0000000..5023b14
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/main/java/io/hawt/util/introspect/support/Packages.java"
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.util.introspect.support;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class Packages {
+ private static final transient Logger LOG = LoggerFactory.getLogger(Packages.class);
+
+ public static Package[] findPackagesForClassLoader(ClassLoader loader) {
+ IntrospectClassLoader introspectClassLoader = new IntrospectClassLoader(loader);
+ return introspectClassLoader.getPackages();
+ }
+/*
+
+ public static Map getPackageSet(List classLoaders) {
+ Set packages = new HashSet();
+ add(packages, Package.getPackages());
+ for (ClassLoader classLoader : classLoaders) {
+ Package[] loaderPackages = findPackagesForClassLoader(classLoader);
+ add(packages, loaderPackages);
+ }
+ SortedSet names = new TreeSet();
+ for (Package aPackage : packages) {
+ names.add(aPackage.getName());
+ }
+ for (String name : names) {
+ LOG.info("Got package " + name);
+ }
+ return packages;
+ }
+*/
+
+ public static Map getPackageMap(List classLoaders, Set ignorePackages) {
+ Map answer = new HashMap();
+
+ ClassLoader[] globalClassLoaders = {Thread.currentThread().getContextClassLoader(),
+ ClassScanner.class.getClassLoader()};
+
+ Set packages = new HashSet();
+ add(answer, Package.getPackages(), globalClassLoaders, ignorePackages);
+
+ ClassLoader[] classLoaderArray = new ClassLoader[classLoaders.size()];
+ classLoaders.toArray(classLoaderArray);
+
+ for (ClassLoader classLoader : classLoaders) {
+ Package[] loaderPackages = findPackagesForClassLoader(classLoader);
+ add(answer, loaderPackages, classLoaderArray, ignorePackages);
+ }
+ SortedSet names = new TreeSet();
+ for (Package aPackage : packages) {
+ names.add(aPackage.getName());
+ }
+ for (String name : names) {
+ LOG.info("Got package " + name);
+ }
+ return answer;
+ }
+
+ protected static void add(Map answer, Package[] packages, ClassLoader[] classLoaders, Set ignorePackages) {
+ if (packages != null) {
+ for (Package aPackage : packages) {
+ String name = aPackage.getName();
+ if (!ignorePackages.contains(name)) {
+ answer.put(aPackage, classLoaders);
+ }
+ }
+ }
+ }
+
+ protected static class IntrospectClassLoader extends ClassLoader {
+ public IntrospectClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ public Package[] getPackages() {
+ return super.getPackages();
+ }
+
+ @Override
+ public Package getPackage(String name) {
+ return super.getPackage(name);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/java/io/hawt/util/HostsTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/java/io/hawt/util/HostsTest.java"
new file mode 100755
index 0000000..58c5983
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/java/io/hawt/util/HostsTest.java"
@@ -0,0 +1,51 @@
+package io.hawt.util;
+
+import org.junit.Test;
+
+import java.net.InetAddress;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+public class HostsTest {
+
+ @Test
+ public void getNetworkInterfaceAddresses() throws Exception {
+ Map> includeLoopback = Hosts.getNetworkInterfaceAddresses(true);
+ assertFalse(includeLoopback.isEmpty());
+ assertLoopback("Should include loopback", true, includeLoopback);
+
+ Map> noLoopback = Hosts.getNetworkInterfaceAddresses(false);
+ assertFalse(noLoopback.isEmpty());
+ assertLoopback("Should not include loopback", false, noLoopback);
+ }
+
+ private static void assertLoopback(String message, boolean expected, Map> actual) {
+ boolean loopback = false;
+ for (Set addresses : actual.values()) {
+ for (InetAddress address : addresses) {
+ loopback = loopback || address.isLoopbackAddress();
+ }
+ }
+ assertEquals(message, expected, loopback);
+ }
+
+ @Test
+ public void getAddresses() throws Exception {
+ assertFalse(Hosts.getAddresses().isEmpty());
+ }
+
+ @Test
+ public void getLocalHostName() throws Exception {
+ assertNotNull(Hosts.getLocalHostName());
+ }
+
+ @Test
+ public void getLocalIp() throws Exception {
+ assertNotNull(Hosts.getLocalIp());
+
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/java/io/hawt/util/StringsTest.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/java/io/hawt/util/StringsTest.java"
new file mode 100755
index 0000000..5808183
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/java/io/hawt/util/StringsTest.java"
@@ -0,0 +1,165 @@
+package io.hawt.util;
+
+import java.util.Arrays;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+@RunWith(Enclosed.class)
+public abstract class StringsTest {
+
+ public static class SplitTest {
+
+ @Test
+ public void split() {
+ assertThat(Strings.split("abc", ","), is(Arrays.asList("abc")));
+ assertThat(Strings.split("a,b,c", ","), is(Arrays.asList("a", "b", "c")));
+ assertThat(Strings.split("a, b, c", ","), is(Arrays.asList("a", "b", "c")));
+ assertThat(Strings.split(",a,,b,,c,", ","), is(Arrays.asList("a", "b", "c")));
+ try {
+ Strings.split(null, ",");
+ fail();
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ try {
+ Strings.split("a, b, c", null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ }
+ }
+
+ @RunWith(Parameterized.class)
+ public static class CleanPathTest {
+
+ @Parameters(name = "\"{0}\" -> \"{1}\"")
+ public static Object[][] params() {
+ return new Object[][] { // @formatter:off
+ { "", "" },
+ { " ", " " },
+ { "/", "/" },
+ { "a", "a" },
+ { "/a", "/a" },
+ { "a/", "a" },
+ { "/a/", "/a" },
+ { "//a/", "/a" },
+ { "/a//", "/a" },
+ { "//a//", "/a" },
+ { "/a/b/", "/a/b" },
+ { "/a///b/", "/a/b" }
+ }; // @formatter:on
+ }
+
+ private final String input;
+ private final String expected;
+
+ public CleanPathTest(final String input, final String expected) {
+ this.input = input;
+ this.expected = expected;
+ }
+
+ @Test
+ public void test() {
+ assertThat(Strings.cleanPath(input), CoreMatchers.equalTo(expected));
+ }
+ }
+
+ @RunWith(Parameterized.class)
+ public static class WebContextPathFromSingleComponentTest {
+
+ @Parameters(name = "\"{0}\" -> \"{1}\"")
+ public static Object[][] params() {
+ return new Object[][] { // @formatter:off
+ { null, "" },
+ { "", "" },
+ { " ", "/ " },
+ { "/", "" },
+ { "a", "/a" },
+ { "/a", "/a" },
+ { "a/", "/a" },
+ { "/a/", "/a" },
+ { "//a/", "/a" },
+ { "/a//", "/a" },
+ { "//a//", "/a" },
+ { "/a/b/", "/a/b" },
+ { "/a///b/", "/a/b" }
+ }; // @formatter:on
+ }
+
+ private final String input;
+ private final String expected;
+
+ public WebContextPathFromSingleComponentTest(final String input,
+ final String expected) {
+ this.input = input;
+ this.expected = expected;
+ }
+
+ @Test
+ public void test() {
+ assertThat(Strings.webContextPath(input),
+ CoreMatchers.equalTo(expected));
+ }
+ }
+
+ @RunWith(Parameterized.class)
+ public static class WebContextPathFromMultipleComponentsTest {
+
+ @Parameters
+ public static Object[][] params() {
+ return new Object[][][] { // @formatter:off
+ { { null, "" } },
+ { {"", "" } },
+ { { " ", "/ " } },
+ { { "/", "" } },
+ { { "a", "/a" } },
+ { { "/a", "/a" } },
+ { { "a/", "/a" } },
+ { { "/a/", "/a" } },
+ { { "//a/", "/a" } },
+ { { "/a//", "/a" } },
+ { { "//a//", "/a" } },
+ { { null, null, "" } },
+ { { null, "a", "/a" } },
+ { { "a", null, "/a" } },
+ { { "a", "b", "/a/b" } },
+ { { "/a", "b", "/a/b" } },
+ { { "a", "/b", "/a/b" } },
+ { { "/a", "/b", "/a/b" } },
+ { { "/a/", "b", "/a/b" } },
+ { { "/a/", "/b", "/a/b" } },
+ { { "/a/", "/b/", "/a/b" } },
+ { { "/a//", "/b//", "/a/b" } },
+ }; // @formatter:on
+ }
+
+ private final String first;
+ private final String[] more;
+ private final String expected;
+
+ public WebContextPathFromMultipleComponentsTest(final Object... input) {
+ this.first = (String) input[0];
+ this.more = input.length > 2
+ ? Arrays.copyOfRange(input, 1, input.length - 1, String[].class)
+ : new String[0];
+ this.expected = (String) input[input.length - 1];
+ }
+
+ @Test
+ public void test() {
+ assertThat(Strings.webContextPath(first, more),
+ CoreMatchers.equalTo(expected));
+ }
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/resources/log4j.properties"
new file mode 100755
index 0000000..70f6cb4
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-util/src/test/resources/log4j.properties"
@@ -0,0 +1,18 @@
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, stdout, out
+
+#log4j.logger.io.hawt.introspect=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/test.log
+log4j.appender.out.append=true
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/README.md" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/README.md"
new file mode 100755
index 0000000..00c5528
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/README.md"
@@ -0,0 +1,17 @@
+## hawtio web console for Java
+
+This is the default hawtio web console for Java that is a distributed as a `.war` deployment unit.
+
+### Running locally
+
+To try the console you can run it from command line with
+
+ mvn wildfly:run
+
+Then the console is accessible from
+
+#### Using Jetty
+
+If you want to run the console on Jetty instead of Undertow (WildFly), run it with
+
+ mvn jetty:run-war
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/login.conf" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/login.conf"
new file mode 100755
index 0000000..1fa22b6
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/login.conf"
@@ -0,0 +1,4 @@
+* {
+ org.eclipse.jetty.jaas.spi.PropertyFileLoginModule required
+ file="etc/users.properties";
+};
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/security.cli" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/security.cli"
new file mode 100755
index 0000000..710eebe
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/security.cli"
@@ -0,0 +1,13 @@
+# Adds hawtio security domain configuration to WildFly
+
+batch
+
+/system-property=hawtio.authenticationEnabled/:add(value=true)
+/system-property=hawtio.realm/:add(value=hawtio-domain)
+/subsystem=security/security-domain=hawtio-domain/:add(cache-type=default)
+/subsystem=security/security-domain=hawtio-domain/authentication=classic:add
+/subsystem=security/security-domain=hawtio-domain/authentication=classic/login-module=hawtio-domain/:add(code=RealmDirect,flag=optional,module-options=realm=ManagementRealm)
+
+run-batch
+
+reload
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/users.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/users.properties"
new file mode 100755
index 0000000..347ac67
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/etc/users.properties"
@@ -0,0 +1 @@
+admin=admin,admin,viewer
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/pom.xml"
new file mode 100755
index 0000000..eb0ce83
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/pom.xml"
@@ -0,0 +1,255 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+
+
+ 4.0.0
+ hawtio-war
+ war
+ ${project.artifactId}
+ hawtio :: Web Console
+
+
+ hawtio
+
+
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${servlet-api-version}
+ provided
+
+
+
+
+ io.hawt
+ hawtio-core
+ ${project.version}
+
+
+ io.hawt
+ hawtio-system
+ ${project.version}
+
+
+ io.hawt
+ hawtio-util
+ ${project.version}
+
+
+
+ io.hawt
+ hawtio-console-assembly
+ ${project.version}
+
+
+
+
+ io.hawt
+ hawtio-local-jvm-mbean
+ ${project.version}
+
+
+
+
+ org.jolokia
+ jolokia-core
+ ${jolokia-version}
+
+
+ org.jolokia
+ jolokia-jvm
+ ${jolokia-version}
+ agent
+
+
+
+
+ com.google.guava
+ guava
+ ${guava-version}
+
+
+
+
+ org.apache.aries.blueprint
+ org.apache.aries.blueprint.web
+ ${blueprint-web-version}
+
+
+ org.apache.geronimo.specs
+ geronimo-servlet_2.5_spec
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j-version}
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+
+
+
+
+
+ ${finalName}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+
+
+ ../hawtio-console-assembly/dist/
+
+ **/*.*
+
+
+
+
+ ${project.build.directory}/classes/META-INF/MANIFEST.MF
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ ${maven-bundle-plugin-version}
+
+
+ bundle-manifest
+ process-classes
+
+ manifest
+
+
+
+
+
+ war
+
+
+ ${context}
+ ${context}
+
+ WEB-INF/lib
+ *;scope=compile|runtime;artifactId=!org.osgi.enterprise|org.osgi.core
+ true
+
+
+ org.apache.commons.logging;resolution:=optional,
+ org.slf4j;resolution:=optional;version="[1.6,2)",
+ org.apache.karaf.jaas.boot.principal;resolution:=optional,
+ !org.slf4j.impl,
+ !org.apache.avalon*,
+ !org.apache.log*,
+ !javax.jmdns*,!javax.jms*,!javax.portlet*,
+ !com.ibm.uvm.tools*,
+ !com.sun.jdmk.comm*,!com.sun.net*,!com.sun.tools*,!sun.security.x509*,
+ !com.google.errorprone.annotations.concurrent,
+ *
+
+
+ !*
+
+
+ WEB-INF/classes
+ ${project.description}
+ ${project.groupId}.${project.artifactId}
+ hawtio osgi
+ ${project.version}
+
+
+
+
+
+ org.wildfly.plugins
+ wildfly-maven-plugin
+ ${wildfly-maven-plugin-version}
+
+
+ org.wildfly
+ wildfly-servlet-dist
+ ${wildfly-version}
+
+
+
+ admin
+ admin
+
+
+
+
+
+
+
+
+
+ -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8787
+
+
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ ${jetty-version}
+
+ ../hawtio-console-assembly/
+ 1
+
+ ${context}
+
+ ${project.build.directory}/${project.name}/WEB-INF/classes
+ stop
+ 9999
+
+
+ java.security.auth.login.config
+ ${project.basedir}/etc/login.conf
+
+
+
+
+
+
+ maven-clean-plugin
+
+
+
+ ${basedir}/overlays
+
+ **/*.*
+
+ false
+
+
+
+
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/java/io/hawt/blueprint/HawtioBlueprintContextListener.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/java/io/hawt/blueprint/HawtioBlueprintContextListener.java"
new file mode 100755
index 0000000..93f0998
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/java/io/hawt/blueprint/HawtioBlueprintContextListener.java"
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2013 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.hawt.blueprint;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.apache.aries.blueprint.container.BlueprintContainerImpl;
+
+/**
+ * Initialises all the blueprint XML files called META-INF/blueprint.xml on the classpath
+ */
+public class HawtioBlueprintContextListener implements ServletContextListener {
+
+ public static final String CONTAINER_ATTRIBUTE = "org.apache.aries.blueprint.container";
+
+ public static final String LOCATION = "blueprintLocation";
+
+ public static final String PROPERTIES = "blueprintProperties";
+
+ public static final String DEFAULT_LOCATION = "META-INF/blueprint.xml";
+
+ public void contextInitialized(ServletContextEvent event) {
+ ServletContext servletContext = event.getServletContext();
+ String location = servletContext.getInitParameter(LOCATION);
+ if (location == null) {
+ location = DEFAULT_LOCATION;
+ }
+ List resourcePaths = new ArrayList();
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Enumeration resources = classLoader.getResources(location);
+ while (resources.hasMoreElements()) {
+ resourcePaths.add(resources.nextElement());
+ }
+ Collections.sort(resourcePaths, new Comparator() {
+ @Override
+ public int compare(URL o1, URL o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+ });
+ servletContext.log("Loading Blueprint contexts " + resourcePaths);
+
+ Map properties = new HashMap();
+ String propLocations = servletContext.getInitParameter(PROPERTIES);
+ if (propLocations != null) {
+ for (String propLoc : propLocations.split(",")) {
+ Enumeration propUrl = classLoader.getResources(propLoc);
+ while (propUrl.hasMoreElements()) {
+ URL url = propUrl.nextElement();
+ InputStream is = url.openStream();
+ try {
+ Properties props = new Properties();
+ props.load(is);
+ Enumeration names = props.propertyNames();
+ while (names.hasMoreElements()) {
+ String key = names.nextElement().toString();
+ properties.put(key, props.getProperty(key));
+ }
+ } finally {
+ is.close();
+ }
+ }
+ }
+ }
+ appendEnvironmentVariablesAndSystemProperties(servletContext, properties);
+
+ BlueprintContainerImpl container = new BlueprintContainerImpl(classLoader, resourcePaths, properties, true);
+ servletContext.setAttribute(CONTAINER_ATTRIBUTE, container);
+ } catch (Exception e) {
+ servletContext.log("Failed to startup blueprint container. " + e, e);
+ }
+ }
+
+ protected void appendEnvironmentVariablesAndSystemProperties(ServletContext servletContext, Map properties) {
+ try {
+ Properties sysProperties = System.getProperties();
+ Set> sysEntries = sysProperties.entrySet();
+ for (Map.Entry sysEntry : sysEntries) {
+ Object key = sysEntry.getKey();
+ Object value = sysEntry.getValue();
+ if (key != null && value != null) {
+ String propertyName = key.toString();
+ String propertyValue = value.toString();
+ if (!properties.containsKey(propertyName)) {
+ properties.put(propertyName, propertyValue);
+ }
+ }
+ }
+ Map env = System.getenv();
+ if (env != null) {
+ Set> entries = env.entrySet();
+ for (Map.Entry entry : entries) {
+ String name = entry.getKey();
+ String propertyName = convertEnvironmentVariableToSystemProperty(name);
+ properties.put(propertyName, entry.getValue());
+ }
+ }
+ } catch (Exception e) {
+ servletContext.log("Failed to load environment variables: " + e, e);
+ }
+ }
+
+ protected String convertEnvironmentVariableToSystemProperty(String name) {
+ // system properties may be upper and lower case so lets not mess with the case
+ // lets convert _ to dots so that folks can specify dots in env vars
+ return name.replace('_', '.');
+ }
+
+ public void contextDestroyed(ServletContextEvent event) {
+ ServletContext servletContext = event.getServletContext();
+ Object container = servletContext.getAttribute(CONTAINER_ATTRIBUTE);
+ if (container instanceof BlueprintContainerImpl) {
+ BlueprintContainerImpl blueprint = (BlueprintContainerImpl) container;
+ blueprint.destroy();
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/resources/blueprint.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/resources/blueprint.properties"
new file mode 100755
index 0000000..860fdbe
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/resources/blueprint.properties"
@@ -0,0 +1,5 @@
+# the properties file used to override blueprint configuration properties:
+# http://aries.apache.org/modules/blueprintweb.html
+#
+# for hawtio configuration options see:
+# https://github.com/hawtio/hawtio/blob/master/docs/Configuration.md
\ No newline at end of file
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/resources/log4j.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/resources/log4j.properties"
new file mode 100755
index 0000000..f699cef
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/resources/log4j.properties"
@@ -0,0 +1,7 @@
+log4j.rootLogger=INFO, console
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n
+log4j.appender.console.threshold=INFO
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/webapp/WEB-INF/web.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/webapp/WEB-INF/web.xml"
new file mode 100755
index 0000000..461e79f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio-war/src/main/webapp/WEB-INF/web.xml"
@@ -0,0 +1,304 @@
+
+
+
+ hawtio
+ hawtio
+
+
+ Enable/disable hawtio's authentication filter, value is really a boolean
+ hawtio/authenticationEnabled
+ java.lang.String
+ true
+
+
+
+ Authorized user role, empty string disables authorization
+ hawtio/role
+ java.lang.String
+
+
+
+
+ JAAS classname that would contain the role principal, empty string disables authorization
+ hawtio/rolePrincipalClasses
+ java.lang.String
+
+
+
+
+ JAAS realm used to authenticate users
+ hawtio/realm
+ java.lang.String
+ *
+
+
+
+ AuthenticationContainerDiscovery classes divided by comma, used to discover container environments
+ hawtio/authenticationContainerDiscoveryClasses
+ java.lang.String
+ io.hawt.web.tomcat.TomcatAuthenticationContainerDiscovery
+
+
+
+ Enable/disable Keycloak integration. Value is really a boolean
+ hawtio/keycloakEnabled
+ java.lang.String
+ false
+
+
+
+ Keycloak config file used for frontend. Will use default location if not provided
+ hawtio/keycloakClientConfig
+ java.lang.String
+
+
+
+
+ The maximum time interval, in seconds, that the servlet container will keep this session open between client accesses.
+ hawtio/sessionTimeout
+ java.lang.String
+
+
+
+
+ SessionExpiryFilter
+ io.hawt.web.auth.SessionExpiryFilter
+
+
+ SessionExpiryFilter
+ /*
+
+
+
+ cache
+ io.hawt.web.filters.CacheHeadersFilter
+
+
+ cache
+ /*
+
+
+
+ CORSFilter
+ io.hawt.web.filters.CORSFilter
+
+
+ CORSFilter
+ /*
+
+
+
+ XFrameOptionsFilter
+ io.hawt.web.filters.XFrameOptionsFilter
+
+
+ XFrameOptionsFilter
+ /*
+
+
+
+ XXSSProtectionFilter
+ io.hawt.web.filters.XXSSProtectionFilter
+
+
+ XXSSProtectionFilter
+ /*
+
+
+
+ XContentTypeOptionsFilter
+ io.hawt.web.filters.XContentTypeOptionsFilter
+
+
+ XContentTypeOptionsFilter
+ /*
+
+
+
+ ContentSecurityPolicyFilter
+ io.hawt.web.filters.ContentSecurityPolicyFilter
+
+
+ ContentSecurityPolicyFilter
+ /*
+
+
+
+ StrictTransportSecurityFilter
+ io.hawt.web.filters.StrictTransportSecurityFilter
+
+
+ StrictTransportSecurityFilter
+ /*
+
+
+
+ PublicKeyPinningFilter
+ io.hawt.web.filters.PublicKeyPinningFilter
+
+
+ PublicKeyPinningFilter
+ /*
+
+
+
+ AuthenticationFilter
+ io.hawt.web.auth.AuthenticationFilter
+
+
+ AuthenticationFilter
+ /jolokia/*
+
+
+
+ LoginRedirectFilter
+ io.hawt.web.auth.LoginRedirectFilter
+
+
+ LoginRedirectFilter
+ /*
+
+
+
+ BaseTagHrefFilter
+ io.hawt.web.filters.BaseTagHrefFilter
+
+
+ BaseTagHrefFilter
+ /
+ /index.html
+ /login.html
+ ERROR
+ FORWARD
+ REQUEST
+
+
+
+ jolokia-agent
+ io.hawt.web.servlets.JolokiaConfiguredAgentServlet
+
+ mbeanQualifier
+ qualifier=hawtio
+
+
+
+ allowErrorDetails
+ false
+
+
+ includeStackTrace
+ false
+
+
+ restrictorClass
+ io.hawt.system.RBACRestrictor
+
+ 1
+
+
+
+ jolokia-agent
+ /jolokia/*
+
+
+
+ jolokia-proxy
+ io.hawt.web.proxy.ProxyServlet
+
+
+ proxyWhitelist
+
+ localhost,
+ 127.0.0.1
+
+
+ 1
+
+
+ jolokia-proxy
+ /proxy/*
+
+
+
+ user
+ io.hawt.web.auth.keycloak.KeycloakUserServlet
+
+
+ user
+ /user/*
+
+
+
+ login
+ io.hawt.web.auth.LoginServlet
+
+
+ login
+ /auth/login
+
+
+
+ logout
+ io.hawt.web.auth.LogoutServlet
+
+
+ logout
+ /auth/logout
+
+
+
+ keycloak
+ io.hawt.web.auth.keycloak.KeycloakServlet
+
+
+ keycloak
+ /keycloak/*
+
+
+
+ woff
+ application/font-woff
+
+
+
+ io.hawt.HawtioContextListener
+
+
+
+ io.hawt.blueprint.HawtioBlueprintContextListener
+
+
+
+ blueprintProperties
+ blueprint.properties
+
+
+ blueprintLocation
+ OSGI-INF/blueprint/blueprint.xml
+
+
+
+ 404
+ /index.html
+
+
+
+ index.html
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio.properties" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio.properties"
new file mode 100755
index 0000000..33cdd6a
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/hawtio.properties"
@@ -0,0 +1,65 @@
+# Modify this file, publish it on your web site and contact
+# JBoss middleware team to set project matrix to parse this file
+# for your project information
+
+# Required fields
+#######################################################
+# should be something like /project or /project/subproject. Only alphanumeric
+# characters are allowed (no spaces)!
+nodePath=/hawtio
+# Human readable name of the project. Everything after " - " is cut off.
+projectName=hawtio
+# Main URL to your project
+homePage=http://hawt.io
+
+# Miscellaneous fields
+#######################################################
+description=A modular Web console for managing Java applications
+# ASL, LGPL, LGPL2, LGPL3, EPL, other
+license=ASL
+# if license is other, fill the URL of the license here
+otherLicenseLink=
+specialIcon=
+archived=
+excludeInProjectMatrix=
+subProjects=
+
+# Downloads
+#######################################################
+downloadsLink=https://github.com/hawtio/hawtio/releases
+
+# Documents
+#######################################################
+docsLink=http://hawt.io/docs/
+
+# Community links
+#######################################################
+communityLink=http://hawt.io/community/
+knowledgeBaseLink=
+userForumLink=
+devForumLink=
+mailingListLink=https://groups.google.com/forum/#!forum/hawtio
+chatLink=http://webchat.freenode.net/?channels=hawtio
+blogLink=
+twitterLink=https://twitter.com/hawtio
+
+# Source code links
+#######################################################
+srcLink=
+anonymousLink=
+committerLink=
+fisheyeLink=
+viewvcLink=
+githubLink=https://github.com/hawtio/hawtio
+anonymousGitLink=
+committerGitLink=
+
+# Build links
+#######################################################
+buildLink=
+hudsonLink=
+
+# Issue tracker links
+#######################################################
+issueTrackerLink=
+jiraLink=https://github.com/hawtio/hawtio/issues?q=is%3Aopen
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/pom.xml" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/pom.xml"
new file mode 100755
index 0000000..002938e
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/pom.xml"
@@ -0,0 +1,115 @@
+
+
+
+ io.hawt
+ project
+ 2.5.0
+ ../..
+
+
+ 4.0.0
+ hawtio-osgi-jmx
+ bundle
+ ${project.artifactId}
+ hawtio :: OSGi-related JMX MBeans
+
+
+
+ org.osgi
+ org.osgi.core
+ ${osgi-version}
+ provided
+
+
+
+ org.osgi
+ org.osgi.enterprise
+ ${osgi-version}
+ provided
+
+
+
+ org.apache.karaf.management
+ org.apache.karaf.management.server
+ ${karaf-version}
+ provided
+
+
+
+ commons-codec
+ commons-codec
+ ${commons-codec-version}
+
+
+
+
+ junit
+ junit
+ ${junit-version}
+ test
+
+
+ org.hamcrest
+ hamcrest-library
+ 1.3
+ test
+
+
+ org.mockito
+ mockito-core
+ 2.20.0
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson-version}
+ test
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.7
+
+
+ org.slf4j
+ slf4j-log4j12
+ ${slf4j-version}
+ test
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ ${maven-bundle-plugin-version}
+ true
+
+
+ bundle-manifest
+ process-classes
+
+ manifest
+
+
+
+
+
+ ${project.description}
+ ${project.groupId}.${project.artifactId}
+ io.hawt.osgi.jmx.Activator
+ Additional JMX APIs into the OSGi Framework, used by hawt.io browser-based client.
+
+ org.apache.karaf.management;version="${karaf-version-range}",
+ *
+
+
+ org.apache.commons.codec*,io.hawt.osgi.jmx
+
+
+
+
+
+
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/Activator.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/Activator.java"
new file mode 100755
index 0000000..d79f408
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/Activator.java"
@@ -0,0 +1,31 @@
+package io.hawt.osgi.jmx;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator {
+
+ private OSGiTools osgiTools;
+ private ConfigAdmin configAdmin;
+ private RBACDecorator rbacDecorator;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ osgiTools = new OSGiTools(context);
+ osgiTools.init();
+
+ configAdmin = new ConfigAdmin(context);
+ configAdmin.init();
+
+ rbacDecorator = new RBACDecorator(context);
+ rbacDecorator.init();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ rbacDecorator.destroy();
+ configAdmin.destroy();
+ osgiTools.destroy();
+ }
+
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/ConfigAdmin.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/ConfigAdmin.java"
new file mode 100755
index 0000000..60bce87
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/ConfigAdmin.java"
@@ -0,0 +1,59 @@
+package io.hawt.osgi.jmx;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.util.Hashtable;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+public class ConfigAdmin implements ConfigAdminMXBean {
+ private final BundleContext bundleContext;
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+
+ ConfigAdmin(BundleContext bc) {
+ bundleContext = bc;
+ }
+
+ void init() throws Exception {
+ if (objectName == null) {
+ objectName = new ObjectName("hawtio:type=ConfigAdmin");
+ }
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ mBeanServer.registerMBean(this, objectName);
+ }
+
+ void destroy() throws Exception {
+ if (objectName != null && mBeanServer != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+
+ @Override
+ public void configAdminUpdate(String pid, Map data) {
+ ServiceReference sref = bundleContext.getServiceReference(ConfigurationAdmin.class.getName());
+ if (sref == null) {
+ throw new IllegalStateException("The configuration admin service cannot be found.");
+ }
+
+ try {
+ ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(sref);
+ if (ca == null) {
+ throw new IllegalStateException("The configuration admin service cannot be found.");
+ }
+ Configuration config = ca.getConfiguration(pid, null);
+ config.update(new Hashtable(data));
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ } finally {
+ bundleContext.ungetService(sref);
+ }
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/ConfigAdminMXBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/ConfigAdminMXBean.java"
new file mode 100755
index 0000000..673079c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/ConfigAdminMXBean.java"
@@ -0,0 +1,12 @@
+package io.hawt.osgi.jmx;
+
+import java.util.Map;
+
+/**
+ * This MXBean is to get around a limitation in Jolokia (1.1.2) which prevents it
+ * from working with JMX APIs that take a TabularData argument such as
+ * {@code ConfigurationAdminMBean.html.update(String pid, TabularData properties)}.
+ */
+public interface ConfigAdminMXBean {
+ void configAdminUpdate(String pid, Map data);
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/OSGiTools.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/OSGiTools.java"
new file mode 100755
index 0000000..563195f
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/OSGiTools.java"
@@ -0,0 +1,69 @@
+package io.hawt.osgi.jmx;
+
+import java.lang.management.ManagementFactory;
+import java.net.URL;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+
+public class OSGiTools implements OSGiToolsMXBean {
+ private final BundleContext bundleContext;
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+
+ OSGiTools(BundleContext bc) {
+ bundleContext = bc;
+ }
+
+ void init() throws Exception {
+ if (objectName == null) {
+ objectName = new ObjectName("hawtio:type=OSGiTools");
+ }
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ mBeanServer.registerMBean(this, objectName);
+ }
+
+ void destroy() throws Exception {
+ if (objectName != null && mBeanServer != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+
+ @Override
+ public long getLoadClassOrigin(long bundleID, String clazz) {
+ Bundle b = bundleContext.getBundle(bundleID);
+ if (b == null)
+ throw new IllegalArgumentException("Not a valid bundle ID: " + bundleID);
+
+ try {
+ Class> cls = b.loadClass(clazz);
+ ClassLoader classLoader = cls.getClassLoader();
+ if (classLoader instanceof BundleReference)
+ return ((BundleReference) classLoader).getBundle().getBundleId();
+ else
+ return 0;
+ } catch (ClassNotFoundException e) {
+ }
+
+ return -1;
+ }
+
+ @Override
+ public String getResourceURL(long bundleID, String resource) {
+ Bundle b = bundleContext.getBundle(bundleID);
+ if (b == null)
+ throw new IllegalArgumentException("Not a valid bundle ID: " + bundleID);
+
+ URL res = b.getResource(resource);
+ if (res == null)
+ return null;
+ else
+ return res.toString();
+ }
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/OSGiToolsMXBean.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/OSGiToolsMXBean.java"
new file mode 100755
index 0000000..11c6192
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/OSGiToolsMXBean.java"
@@ -0,0 +1,22 @@
+package io.hawt.osgi.jmx;
+
+public interface OSGiToolsMXBean {
+ /**
+ * Returns from what bundle the given class was loaded, when requested in the context of a certain bundle.
+ * @param bundleID The bundle to load the class from.
+ * @param clazz The class name to load.
+ * @return The bundle that served the class or -1 if the class could not be loaded.
+ * @throws IllegalArgumentException if an invalid bundle ID is provided.
+ */
+ long getLoadClassOrigin(long bundleID, String clazz);
+
+ /**
+ * Returns the URL where the requested resource was found, when looked up in the context of a certain bundle.
+ * @param bundleID The bundle to load the class from.
+ * @param resource The resource name to load. The format is as defined in {@code ClassLoader.getResource}.
+ * @return The URL where the bundle with bundleID can find the resource in String form. If the resource
+ * cannot be found {@code null} is returned.
+ * @throws IllegalArgumentException if an invalid bundle ID is provided.
+ */
+ String getResourceURL(long bundleID, String resource);
+}
diff --git "a/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/RBACDecorator.java" "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/RBACDecorator.java"
new file mode 100755
index 0000000..69e522c
--- /dev/null
+++ "b/\343\200\22004\343\200\221SSRF \346\274\217\346\264\236\345\216\237\347\220\206\344\270\216\345\256\236\351\231\205\346\241\210\344\276\213\344\273\213\347\273\215/hawtio-hawtio-2.5.0/platforms/hawtio-osgi-jmx/src/main/java/io/hawt/osgi/jmx/RBACDecorator.java"
@@ -0,0 +1,611 @@
+/**
+ * Copyright 2005-2016 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.hawt.osgi.jmx;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.management.ManagementFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.karaf.management.JMXSecurityMBean;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An MBean that may be used by hawtio:type=security,name=RBACRegistry to decorate optimized
+ * jolokia list operation with RBAC info.
+ */
+public class RBACDecorator implements RBACDecoratorMBean {
+
+ public static Logger LOG = LoggerFactory.getLogger(RBACDecorator.class);
+
+ private static final String JMX_ACL_PID_PREFIX = "jmx.acl";
+ private static final String JMX_OBJECTNAME_PROPERTY_WILDCARD = "_";
+ private static final Comparator WILDCARD_PID_COMPARATOR = new WildcardPidComparator();
+
+ private final BundleContext bundleContext;
+
+ private ObjectName objectName;
+ private MBeanServer mBeanServer;
+
+ /**
+ * Run with verify mode.
+ */
+ private boolean verify = false;
+
+ public RBACDecorator(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ void init() throws Exception {
+ if (objectName == null) {
+ objectName = new ObjectName("hawtio:type=security,area=jolokia,name=RBACDecorator");
+ }
+ if (mBeanServer == null) {
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ }
+ mBeanServer.registerMBean(this, objectName);
+ }
+
+ void destroy() throws Exception {
+ if (objectName != null && mBeanServer != null) {
+ mBeanServer.unregisterMBean(objectName);
+ }
+ }
+
+ /**
+ * If we have access to {@link ConfigurationAdmin}, we can add RBAC information
+ * @param result
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public void decorate(Map result) throws Exception {
+ try {
+ ServiceReference cmRef = bundleContext.getServiceReference(ConfigurationAdmin.class);
+ ServiceReference jmxSecRef = bundleContext.getServiceReference(JMXSecurityMBean.class);
+ if (cmRef == null || jmxSecRef == null) {
+ return;
+ }
+
+ ConfigurationAdmin configAdmin = bundleContext.getService(cmRef);
+ JMXSecurityMBean jmxSec = bundleContext.getService(jmxSecRef);
+ if (configAdmin == null || jmxSec == null) {
+ return;
+ }
+
+ // 1. each pair of MBean/operation has to be marked with RBAC flag (can/can't invoke)
+ // 2. the information is provided by org.apache.karaf.management.JMXSecurityMBean.canInvoke(java.util.Map)
+ // 3. we'll peek into available configadmin jmx.acl* configs, to see which MBeans/operations have to
+ // be examined and which will produce same results
+ // 4. only then we'll prepare Map as parameter for canInvoke()
+
+ Configuration[] configurations = configAdmin.listConfigurations("(service.pid=jmx.acl*)");
+ if (configurations == null) {
+ return;
+ }
+ List allJmxAclPids = Arrays.stream(configurations)
+ .map(Configuration::getPid)
+ .collect(Collectors.toCollection(LinkedList::new));
+ if (allJmxAclPids.isEmpty()) {
+ return;
+ }
+
+ Map> domains = (Map>) result.get("domains");
+ // cache contains MBeanInfos for different MBeans/ObjectNames
+ Map> cache = (Map>) result.get("cache");
+ // new cache will contain MBeanInfos + RBAC info
+ Map> rbacCache = new HashMap<>();
+
+ // the fact that some MBeans share JSON MBeanInfo doesn't mean that they can share RBAC info
+ // - each MBean's name may have RBAC information configured in different PIDs.
+
+ // when iterating through all repeating MBeans that share MBeanInfo (that doesn't have RBAC info
+ // yet), we have to decide if it'll use shared info after RBAC check or will switch to dedicated
+ // info. we have to be careful not to end with most MBeans *not* sharing MBeanInfo (in case if
+ // somehow the shared info will be "special case" from RBAC point of view)
+
+ Map> queryForMBeans = new HashMap<>();
+ Map> queryForMBeanOperations = new HashMap<>();
+ constructQueries(allJmxAclPids, domains, cache, rbacCache, queryForMBeans, queryForMBeanOperations);
+
+ // RBAC per MBeans (can invoke *any* operation or attribute?)
+ doQueryForMBeans(jmxSec, domains, rbacCache, queryForMBeans);
+
+ // RBAC per { MBean,operation } (can invoke status for each operation)
+ doQueryForMBeanOperations(jmxSec, domains, rbacCache, queryForMBeanOperations);
+
+ result.remove("cache");
+ result.put("cache", rbacCache);
+
+ if (verify) {
+ verify(result);
+ }
+
+ } catch (Exception e) {
+ LOG.error(e.getMessage(), e);
+ // simply do not decorate
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void constructQueries(List allJmxAclPids, Map> domains,
+ Map> cache, Map> rbacCache,
+ Map> queryForMBeans, Map> queryForMBeanOperations) throws MalformedObjectNameException, NoSuchAlgorithmException, UnsupportedEncodingException {
+ for (String domain : domains.keySet()) {
+ Map domainMBeansCheck = new HashMap<>(domains.get(domain)); // shallow copy is ok for a domain
+ Map domainMBeans = domains.get(domain);
+ for (String name : domainMBeansCheck.keySet()) {
+ Object mBeanInfo = domainMBeansCheck.get(name);
+ String fullName = domain + ":" + name;
+ ObjectName oName = new ObjectName(fullName);
+ if (mBeanInfo instanceof Map) {
+ // not shared JSONified MBeanInfo
+ prepareKarafRbacInvocations(fullName, (Map) mBeanInfo,
+ queryForMBeans, queryForMBeanOperations);
+ } else {
+ // shared JSONified MBeanInfo
+
+ // shard mbeanNames sharing MBeanInfo by the hierarchy of jmx.acl* PIDs used to
+ // check RBAC info
+ String key = (String) mBeanInfo;
+ String pidListKey = pidListKey(allJmxAclPids, oName);
+ if (!rbacCache.containsKey(key + ":" + pidListKey)) {
+ // deep copy - "op" / "opByString" may differ per MBeanInfo with different pid list key
+ Map sharedMBeanAndRbacInfo = deepCopy(cache.get(key));
+ rbacCache.put(key + ":" + pidListKey, sharedMBeanAndRbacInfo);
+ // we'll be checking RBAC only for single (first) MBean having this pidListKey
+ prepareKarafRbacInvocations(fullName, sharedMBeanAndRbacInfo,
+ queryForMBeans, queryForMBeanOperations);
+ }
+ // switch key from shared MBeanInfo-only to shared MBean+RbacInfo
+ domainMBeans.put(name, key + ":" + pidListKey);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ static Map deepCopy(Map