Inactive [WEB/DEV/ADMIN] HTTPConsole 0.3.0 - Issue Console Commands Over HTTP [803]

Discussion in 'Inactive/Unsupported Plugins' started by BlueJeansAndRain, Apr 11, 2011.

  1. HTTPConsole - Issue Console Commands Over HTTP
    Version: 0.3.0

    I wrote this because I have a bash script which I use to backup the worlds and do mapping and various other manipulations directly on world data. So, I needed a way for the script to tell the server to save-all, then disable saving to copy the worlds, then re-enable saving. I know there are plugins out there that expose a limited API over HTTP, and there's even one that provides telnet access. But the APIs didn't provide the access I wanted and telnet access is too cumbersome.

    While I was at it I figured I would make it capable of issuing any console command. You never know what you might need :).

    WARNING: If you configure this plugin to listen on an ip address open to the internet, and don't restrict client IP addresses (using the white and black lists) to specific IP addresses you trust, someone will hack your server.

    This is my first plugin... actually this is the first thing I've ever written in Java, so be gentle with my source :p. Suggestions welcome.

    Features:
    • Issue any command over HTTP that you can issue on the console.
    • Change the listener IP address, port, and log-level through the config file.
    • Get back the output of the issued command.
      • This only works for some commands, specifically commands that are not "threaded".
    • Accepts GET and POST (url or json encoded) requests.
    • Client IP address whitelist/blacklist.
    • Host name filtering.
    Trouble Shooting: If it doesn't appear to be working, try the following solutions.
    • Change the "port: 8765" configuration option to a different number. Valid values are 1024 - 65565
    • Make sure your firewall is allowing access to the port.
    Download the plugin Jar

    Source Code
    Usage (open)

    Make requests to http://127.0.0.1:8765/console?command=<command> (assuming you're using the default port and the server is running on localhost). If you're running your server locally, just open up your browser and type http://127.0.0.1:8765/console?command=save-all and SAVE THE WORLD!
    Default config.yml (open)

    Code:
    # The IP address that HTTPConsole will listen on. "any" can be used to listen on
    #  any address.
    # The default is 127.0.0.1
    ip-address: 127.0.0.1
    
    # The TCP listening port that HTTPConsole will bind to.
    # The default is 8765.
    port: 8765
    
    # Controls how important a console message must be to be shown.
    # Possible values: severe, warning, info
    # The default is severe, meaning only severe log messages will be visible.
    log-level: severe
    
    # Controls whether messages beginning with "ConsoleCommandSender:" are filtered
    #  out of the console log.
    # The default value is true.
    filter-command-sender: true
    
    # This sets what ip addresses are not allowed to send requests to HTTPConsole.
    # To add more values, just add more "- ipaddress" lines to the list.
    # Add "- any" (no quotes) to the list to block all ip addresses from connecting
    #  to HTTPConsole.
    # Ranges of ip addresses can be set by using two ip addresses seperated by a
    #  hyphen (-), or by using an asterisk (*) in place of any number.
    # Hyphens and asterisks are special characters in yml files so they will have
    #  to be surrounded by quotes (see examples below).
    client-ip-blacklist:
    #   - 192.168.3.2
    #   - "192.168.4.*"
    #   - "192.168.5.1-192.168.6.254"
    #   - any
    
    # This sets what ip addresses are allowed to send requests to HTTPConsole.
    # All ip addresses and ranges that are valid for the blacklist are also valid
    #  for the whitelist.
    client-ip-whitelist:
    #   Example:
    #   - 192.168.1.100
    #   - "192.168.2.*"
    #   - "192.168.0.1-192.168.0.254"
    #   - any
    
    # This changes the order in which the whitelist and blacklist are checked.
    # Possible Values:
    #
    #  "Deny,Allow"
    #   The whitelist is only checked when an ip address matches the blacklist.
    #   If the ip address matches both lists, it will be allowed. If it matches
    #    neither list, it will be allowed.
    #   This behavior matches the Apache "Deny,Allow" Order directive.
    #   This is the default value.
    #
    #  "Allow,Deny"
    #   The blacklist is only checked when an ip address matches the whitelist.
    #   If the ip address matches both lists, it will be denied. If it matches
    #    neither list, it will be denied.
    #   This behavior matches the Apache "Allow,Deny" Order directive.
    #
    white-black-list-order: "Deny,Allow"
    
    # This is a list of the allowed hostnames (domains) that HTTPConsole will
    #  accept requests on. This means that if someone uses
    #  "http://my.domain.com:8765/console?command=stop" to issue the
    #  stop command to your server, and my.domain.com is not listed below, the
    #  connection will be refused.
    # The one exception to the above rule is that If no hostnames are listed than
    #  any hostname will be allowed.
    # This is similar to virtual hosting except that HTTPConsole only uses the
    #  hostname to allow or deny the request.
    # This feature combined with the cross site scripting restrictions in modern
    #  browsers is designed to make it more difficult for unauthorized people
    #  to target your server from client side (browser) scripts. This does not make
    #  it impossible however as they can always create a proxy if they really want
    #  to send requests from the browser.
    # If any hostnames are listed, requests to bare ip addresses will be denied
    #  unless the ip address is 127.0.0.1.
    # An asterisk (*) in the left most label will match any valid label or labels.
    # At the very least one label and a top level domain (com, org, net, etc.) must
    #  be given per hostname.
    allowed-hosts:
    #   - theanticookie.com
    #   - notch.tumblr.com
    #   - "*.minecraft.net"
    
    # Controls whether connection refused log messages are always sent, or only sent
    #  when log-level is set to info.
    # The default value is false. Connection refused messages will only be visible
    #  if the log-level is set to info.
    always-log-refused-connections: false
    
    Example Backup Bash Script (open)

    This is the backup script I use for my own server.
    Code:
    #!/bin/bash
    BACKUP_DAYS=28
    MINECRAFT_DIR=/home/me/minecraft
    BACKUP_DIR=$MINECRAFT_DIR/backup
    HTTPCONSOLE_URL="http://127.0.0.1:8765"
    
    BASENAME=`basename $0`
    LOCK_FILE=/tmp/$BASENAME.lock
    if [ ! -e "$LOCK_FILE" ]; then
            trap "rm -f \"$LOCK_FILE\"; exit" INT TERM EXIT
            touch $LOCK_FILE
    else
            echo "Backup already running."
            exit
    fi
    
    if [ "$1" == "" ]; then
            echo No worlds specified.
            exit
    fi
    
    TIMESTAMP=`date +%Y-%m-%d_%T`
    
    function console_command
    {
            curl --data-urlencode "command=$*" $HTTPCONSOLE_URL/console
    }
    
    function backup
    {
            WORLD=$1
            SOURCE=$MINECRAFT_DIR/$WORLD/
            TARGET_DIR=$BACKUP_DIR/$WORLD
            TARGET=$TARGET_DIR/$TIMESTAMP
    
            if [ ! -d "$SOURCE" ]; then
                    echo World directory \"$SOURCE\" does not exist.
                    return
            fi
    
            if [ -d "$TARGET_DIR" ]; then
                    if [ -e "$TARGET" ]; then
                            echo Backup path \"$TARGET\" already exists.
                            return
                    fi
    
                    NEWEST_FILE=`ls -t "$TARGET_DIR" 2>/dev/null | head -1`
                    if [ "$NEWEST_FILE" != "" ]; then
                            NEWEST_FILE=$TARGET_DIR/$NEWEST_FILE
                            echo Sourcing Most Recent Backup \"$NEWEST_FILE\"
                            cp -al "$NEWEST_FILE" "$TARGET"
                    else
                            echo No Prior Backups
                    fi
    
                    echo Deleting Backups Older Than $BACKUP_DAYS Days
                    find "$TARGET_DIR/"* -maxdepth 0 -mtime +$BACKUP_DAYS -delete
            elif [ -e "$TARGET_DIR" ]; then
                    echo The backup path \"$TARGET_DIR exists but is not a directory.
                    return
            else
                    mkdir -p "$TARGET_DIR"
            fi
    
            echo Syncing \"$SOURCE\" to \"$TARGET\"
            rsync -a --delete "$SOURCE" "$TARGET"
    }
    
    echo Saving All Minecraft Worlds
    console_command say Backing Up Worlds...
    console_command save-all
    console_command save-off
    echo
    
    for LEVEL in "$@"; do
            echo Backing Up \"$LEVEL\"
            backup $LEVEL
            echo
    done
    
    console_command save-on
    console_command say Backup Complete.
    
    Todo (open)

    • Wait for some log output before completing a request.
    • Return command output.
    • Have the response body be more meaningful than "Recieved Command <command>"
    • Respond to URL or JSON encoded POST requests.
    • Allow the listener address to be changed (not just 127.0.0.1 anymore).
    • Client ip whitelist.
    • Client ip blacklist.
    • Host name filtering.
    • Cookie based sessions. (finished, testing)
    • Get back buffered console output. (finished, testing)
    • Basic/Digest http authorization. (in progress)
    • Command whitelist/blacklist. Allow or disallow some commands.
    • Allow disabling of POST xor GET requests.
    • Write example web page for a console in your browser.
    • Possibly create a new service for restarting the server?
      • Not going to add this because it can be added by getting a plugin that does server restarts and then giving that plugin commands through HTTPConsole.
    • Expose a request handling API to bukkit allowing developers to easily add web service functionality to their plugins.
    • Profit?!
    Change Log (open)


    Version 0.3.0
    • Added blacklist.
    • Added host name filtering.
    • Changed default port to 8765.
    • Bug Fixes
    Version 0.2.1
    • Fixed input stream parsing.
    Version 0.2
    • Reworked logging and output.
    • Handle POST requests (url or json encoded data).
    • Return output from command (easier than I expected).
    • Abstracted a lot of the framework to pave the way for increased future functionality.
    • Listener ip address can be changes via the config.yml file.
    • A client ip address whitelist can be set via the config.yml file.
    Version 0.1
    • Initial Release
     
  2. Thanks :). Glad you like it.
     
  3. Offline

    uncovery

    I am running this through a PHP script that is running on the same server. for a test, I did the following:

    function test() {
    $command = urlencode('permissions -reload all');
    fopen("http://127.0.0.1:8765/console?command=$command", "r");
    }

    on the console (log level info) I receive the following:

    13:36:39 [INFO] HTTPConsole: Request recieved from 127.0.0.1
    13:36:39 [INFO] HTTPConsole: Executing "permissions -reload all"
    13:36:39 [INFO] All world files reloaded.
    13:36:39 [INFO] HTTPConsole: Request handled
    13:36:39 [SEVERE] HTTPConsole: Error writing HTTP request output stream
    13:36:39 [SEVERE] Broken pipe
    java.net.SocketException: Broken pipe
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:132)
    at java.io.DataOutputStream.writeBytes(DataOutputStream.java:276)
    at org.theanticookie.bukkit.httpconsole.HTTPServer.requestHandler(HTTPServer.java:142)
    at org.theanticookie.bukkit.httpconsole.HTTPServer.run(HTTPServer.java:335)

    so the command works fine, but there is this error thrown out. Any idea how to avoid this?
     
  4. I haven't used fopen with it before. I'll take a look and see if i can reproduce it, but in the meantime, try using curl instead of fopen.
     
  5. Offline

    Max Black

    You are god! I hope you keep this updated, because my entire admin site will be based off this (yes, I'm taking a leap of faith ;).
    fyi, file_get_contents works well.
    Thanks again for providing such a great tool for developers not versed in java/bukkit api.
     
  6. Offline

    Grimmy777

    If my port address is not the default address and I register a domain to point to my IP, will they also have to specify a port number in the minecraft client like myworld.net:7070 or can domains point to ports too?
     
  7. Nope, domains only point to addresses, not ports. Browsers will assume port 80 for http requests. You could have a standard web browser catch the address on port 80, and then redirect to port 7070, but that would require that you have apache or nginx or some other browser running on your server also.
     
  8. Offline

    Phaedrus

    Any status update on password protection? :p
     
  9. Offline

    Max Black

    @Phaedrus I feel the IP blacklist/whitelist is more than enough control, and adding passwords would muck up the plugin a bit. If you are running a webserver on your minecraft server, I'd be happy to give you an example page that utilizes password protection.
    Though adding features doesn't (usually) hurt.
     
  10. Offline

    Phaedrus

    See my earlier post to see why blacklist/white list isn't feasible for me.

    http://forums.bukkit.org/threads/we...mmands-over-http-803.12504/page-3#post-265524
     
  11. Offline

    Darazo

    Been getting this error lately:

    Code:
    28.05 20:59:41 [Server] INFO java.net.SocketException: Too many open files
    28.05 20:59:41 [Server] SEVERE Too many open files
    28.05 20:59:41 [Server] SEVERE java.net.SocketException: Too many open files
    28.05 20:59:41 [Server] SEVERE HTTPConsole: Error while handling an HTTP request.
    28.05 20:59:41 [Server] INFO  at org.theanticookie.bukkit.httpconsole.HTTPServer.run(HTTPServer.java:331)
    28.05 20:59:41 [Server] INFO  at java.net.ServerSocket.accept(ServerSocket.java:438)
    28.05 20:59:41 [Server] INFO  at java.net.ServerSocket.implAccept(ServerSocket.java:470)
    28.05 20:59:41 [Server] INFO  at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:375)
    28.05 20:59:41 [Server] INFO  at java.net.PlainSocketImpl.socketAccept(Native Method)
     
  12. I haven't had much time lately so not much progress sorry :/.

    Ruh-ro, that can't be good shaggy. Hmm... I have an idea maybe. I'll take a look Monday. Yay extra day of weekend.
     
  13. Offline

    Crimsonfox

    I'm getting this. I set the listen IP to my home computer to try and test it but to no luck. I simply get "Cannot establish connection", presumably because of this error:

    Code:
    2011-06-04 14:11:02 [SEVERE] HTTPConsole: Failed to create socket on 80.2.187.135:8765
    2011-06-04 14:11:02 [SEVERE] Cannot assign requested address
    java.net.BindException: Cannot assign requested address
        at java.net.PlainSocketImpl.socketBind(Native Method)
        at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:336)
        at java.net.ServerSocket.bind(ServerSocket.java:336)
        at java.net.ServerSocket.<init>(ServerSocket.java:202)
        at org.theanticookie.bukkit.httpconsole.HTTPServer.start(HTTPServer.java:278)
        at org.theanticookie.bukkit.HTTPConsole.onEnable(HTTPConsole.java:182)
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:125)
        at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:750)
        at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:253)
        at org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:134)
        at org.bukkit.craftbukkit.CraftServer.loadPlugins(CraftServer.java:112)
        at org.bukkit.craftbukkit.CraftServer.reload(CraftServer.java:339)
        at org.bukkit.command.SimpleCommandMap$ReloadCommand.execute(SimpleCommandMap.java:247)
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:128)
        at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:281)
        at net.minecraft.server.NetServerHandler.handleCommand(NetServerHandler.java:718)
        at net.minecraft.server.NetServerHandler.chat(NetServerHandler.java:684)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:677)
        at net.minecraft.server.Packet3Chat.a(Packet3Chat.java:32)
        at net.minecraft.server.NetworkManager.b(NetworkManager.java:217)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:75)
        at net.minecraft.server.NetworkListenThread.a(SourceFile:105)
        at net.minecraft.server.MinecraftServer.h(MinecraftServer.java:401)
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:311)
        at net.minecraft.server.ThreadServerApplication.run(SourceFile:422)
    2011-06-04 14:11:02 [INFO] HTTPConsole 0.3.0 is enabled
    Any ideas? Possibly to do with 818 at all?

    Also when disabling HTTP when I /reload I get this:


    Code:
    2011-06-04 14:11:00 [SEVERE] Error occurred while disabling HTTPConsole v0.3.0 (Is it up to date?): null
    java.lang.NullPointerException
        at org.theanticookie.bukkit.httpconsole.HTTPServer.stopServer(HTTPServer.java:301)
        at org.theanticookie.bukkit.HTTPConsole.onDisable(HTTPConsole.java:197)
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:127)
        at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin(JavaPluginLoader.java:771)
        at org.bukkit.plugin.SimplePluginManager.disablePlugin(SimplePluginManager.java:269)
        at org.bukkit.plugin.SimplePluginManager.disablePlugins(SimplePluginManager.java:262)
        at org.bukkit.plugin.SimplePluginManager.clearPlugins(SimplePluginManager.java:290)
        at org.bukkit.craftbukkit.CraftServer.reload(CraftServer.java:311)
        at org.bukkit.command.SimpleCommandMap$ReloadCommand.execute(SimpleCommandMap.java:247)
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:128)
        at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:281)
        at net.minecraft.server.NetServerHandler.handleCommand(NetServerHandler.java:718)
        at net.minecraft.server.NetServerHandler.chat(NetServerHandler.java:684)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:677)
        at net.minecraft.server.Packet3Chat.a(Packet3Chat.java:32)
        at net.minecraft.server.NetworkManager.b(NetworkManager.java:217)
        at net.minecraft.server.NetServerHandler.a(NetServerHandler.java:75)
        at net.minecraft.server.NetworkListenThread.a(SourceFile:105)
        at net.minecraft.server.MinecraftServer.h(MinecraftServer.java:401)
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:311)
        at net.minecraft.server.ThreadServerApplication.run(SourceFile:422)
     
  14. The "cannot assign requested address" would seem to indicate that for some reason that address isn't actually assigned to your computer. If you're behind a NAT (router) then you'll have a local address, not that address which is your public IP. Otherwise, I dunno. Make sure the address is correct.
     
  15. Offline

    Crimsonfox

    Ah, the router would be the problem then, silly me. Cheers, I'll try it and see how it goes. =)
     
  16. Offline

    iama

    hi all !

    i use this very nice plugin, but i have small problem:

    trying to send command "toggle reg" to my server (command for disabling auth)

    /usr/bin/curl 'http://127.0.0.1:8765/console?command=toggle reg'
    [xAuth] Correct Usage: /toggle <reg|changepw|autosave|filter|blankname|verifyip|strike|forcereg>

    try second

    $ /usr/bin/curl http://127.0.0.1:8765/console?command=toggle reg
    [xAuth] Correct Usage: /toggle <reg|changepw|autosave|filter|blankname|verifyip|strike|forcereg>
    curl: (6) Couldn't resolve host 'reg'


    again

    $ /usr/bin/curl "http://127.0.0.1:8765/console?command=toggle reg"
    [xAuth] Correct Usage: /toggle <reg|changepw|autosave|filter|blankname|verifyip|strike|forcereg>

    how can i send command with two words, like "command someon" ? please help me...
     
  17. Offline

    Hrdkr

    Very, very, very useful plugin. Absolutely must have. Thank you so much.
    Also it works with 818, update the thead title.

    You should use:
    Code:
    curl "http://127.0.0.1:8765/console?command=toggle+reg
    Cause it is a HTTP query.
     
  18. Offline

    Max Black

    I see, I would recommend only allowing commands to come from the localhost then. Putting a password into the url of a site is like putting your password on a stickynote on the outside of your laptop. It just isn't secure.
    You could create a small webpage to run; it would accept commands, and return their output.
     
  19. Offline

    keenick4

    Awesome plugin! Will use often!
     
  20. Offline

    alex4108

    OH MY GOD THIS SAVED MY SITUATION.

    Multiple admins for my server, but if we need to do something from the airport, coffee, etc, just log in from the iPhone and run the command. Now the real question is, can anybody rig this into a full blown panel?

    Edit: NVM. I actually have a working PHP Command executer that is secure, and returns the output of your command. Very nice job mr. dev! I'll throw a few dollars your way when I get some funding
     
  21. Offline

    wouter0100

    Works this with a normal command like
    /permissions -reload all?
    Ore
    /permissions [name] parents add [group] (group and name need to be automatichle but i make that..)

    GREAT!
    IT WORK :D
    console?command=pr+-reload+all
    THANKSSS!

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 13, 2016
  22. Offline

    alex4108

    I'm parsing it through include()
    Include will return the output of your command, as well as run it! =)
     
  23. Offline

    nightpool

    Sorry if this was asked before, but what is the benefit of using this over SSH? With puTTY being pretty lightweight and all, wouldn't it be easier to carry a copy around with you; maybe even with keys?
     
  24. Offline

    Ashneil Roy

    Is there any way in PHP to make a variable into a GET pointing to a server? I've done this so far and it works but i don't want to use a text input. I want to use a something like $command as the input and use GET to send it out as a url to the server. (BTW i'm making a control panel for the admins of my server)

    Code:
    <html>
    <form action="http://w3minecraft.servercraft.co:8755/console" method="get">
    command: <input type="text" name="command" />
    <input type="submit" />
    </form>
    </html>
     
  25. Offline

    djrazr

  26. Offline

    Justinwiz

    Use %20 or urlencode().

    Oh, and please... Even though this works fine on build #1000, can someone make a fork of this and update the title with build #1000? Would hate to see this wonderful plugin disappear from the plugin list for inactivity.
     
    Windows_i7_920 likes this.
  27. Offline

    Windows_i7_920

    Agreed. Since I want to use this as an easier way of making a sort of web based control panel, it'd help if it would not die. :p
     
  28. Offline

    Herover

    Hi, I made a site that can control a minecraft server with this plugin.
    http://www.remote.lolbrothers.com/minecraft/httpconsole/
    Don't wory, I won't log you too much :)
    For the want-to-doit-myself, heres my code:
    PHP:
    <?php
    function curl($cmd) {
        
    $c curl_init($_SESSION["IP"]."/console?command=".$cmd);
        
    curl_setopt($cCURLOPT_PORT$_SESSION["port"]);
        
    curl_setopt($cCURLOPT_HEADERfalse);
        
    curl_setopt($cCURLOPT_RETURNTRANSFERtrue);
        
    //EDITs BELOW
        
    curl_setopt($cCURLOPT_CONNECTTIMEOUT1);
        
    curl_setopt($cCURLOPT_TIMEOUT1);
        
    curl_setopt($cCURLOPT_MAXCONNECTS1);
        
    $hh = array(
          
    "Expect:",
          
    // more headers here
        
    );
        
    curl_setopt($cCURLOPT_HTTPHEADER$hh);    //Getting veeeeery slow
        
    $result curl_exec($c);

        
    curl_close($c);
        return 
    $result;
    }
    ?>

    About the security stuff, can't you put in a parameter in the url called "pass"? Even without HTTPS, it would give some security if some unwanted person find the port for access. I think I would use it if it had password protection.
     
  29. We use this plugin A LOT on our server for our website admin panel.

    We also use it to check to see if the server is down by sending the /list command (and if it returns nothing it kills the process and restarts the server).
     
  30. Offline

    Stonebreak

    how i can make this online?
     
  31. Offline

    Jonchun

    What are you asking for?
     

Share This Page