raghur / vim-ghost

Vim/Nvim client for GhostText - Edit browser text areas in Vim/Neovim
333 stars 13 forks source link

Security issues (2) #9

Closed SkyLeach closed 6 years ago

SkyLeach commented 6 years ago

I was looking for how to replicate external editing in vim. Found the plugin vim-ghost and decided to try it.

The problem is that it depends on a direct (not pypi hosted) install from github of this: https://github.com/dpallot/simple-websocket-server

Right, that's strange, but I have a safe-ish firewalled area to test it in.

The first thing I noticed is that simply importing that SimpleWebSocketServer immediately opened an https server publicly. from .SimpleWebSocketServer import *

And one of those imports is SimpleHTTPSServer.py:

'''
The MIT License (MIT)
Copyright (c) 2013 Dave P.
'''

import BaseHTTPServer, SimpleHTTPServer
import ssl

# openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
httpd = BaseHTTPServer.HTTPServer(('', 443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile='./cert.pem', keyfile='./cert.pem', ssl_version=ssl.PROTOCOL_TLSv1)
httpd.serve_forever()

YSK this even opens an https server when opened with jedi from within vim for doing syntax checking. That's unnerving.

I changed it to this, just to test the plugin (which I'm using right now).

'''
The MIT License (MIT)
Copyright (c) 2013 Dave P.
'''

import BaseHTTPServer, SimpleHTTPServer
import ssl

# openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem
# no no no no do not do this
# httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', 443), SimpleHTTPServer.SimpleHTTPRequestHandler)
# httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile='./cert.pem', keyfile='./cert.pem', ssl_version=ssl.PROTOCOL_TLSv1)
# httpd.serve_forever()

def getSimpleHttpServer():
    httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', 443), SimpleHTTPServer.SimpleHTTPRequestHandler)
    httpd.socket = ssl.wrap_socket(httpd.socket, server_side=True, certfile='./cert.pem', keyfile='./cert.pem', ssl_version=ssl.PROTOCOL_TLSv1)
    httpd.serve_forever()

Even so, I still got the firewall warning with a pseudo-random port. So I took a look at vim-ghost.

In ghost.py (under rplugin/python3) lines 94-110:

    @neovim.command('GhostStart', range='', nargs='0')
    def server_start(self, args, range):
        if self.server_started:
            self.nvim.command("echo 'Ghost server already running on port %d'"
                              % self.port)
            logger.info("server already running on port %d", self.port)
            return

        if self.nvim.funcs.exists("g:ghost_port") == 1:
            self.port = self.nvim.api.get_var("ghost_port")
        else:
            self.nvim.api.set_var("ghost_port", self.port)

        self.httpserver = MyHTTPServer(self, ('', self.port),
                                       WebRequestHandler)
        http_server_thread = Thread(target=self.httpserver.serve_forever,
                                    daemon=True)

Again, unless you intend to let people on other machines edit your posts in McDonald's or Starbucks, you really do not want top open a public web socket. I'm not sure how windows does it, but if you open an unbound socket and don't allow it with the firewall, it blocks it for localhost as well. That means it's either insecure, or will not work. That's probably not a good idea.

I changed the code on my copy (that I'm using now) like so: (and got rid of that pesky firewall warning for Python.app)

    @neovim.command('GhostStart', range='', nargs='0')
    def server_start(self, args, range):
        if self.server_started:
            self.nvim.command("echo 'Ghost server already running on port %d'"
                              % self.port)
            logger.info("server already running on port %d", self.port)
            return

        if self.nvim.funcs.exists("g:ghost_port") == 1:
            self.port = self.nvim.api.get_var("ghost_port")
        else:
            self.nvim.api.set_var("ghost_port", self.port)

        self.httpserver = MyHTTPServer(self, ('127.0.0.1', self.port),
                                       WebRequestHandler)
        http_server_thread = Thread(target=self.httpserver.serve_forever,
                                    daemon=True)
SkyLeach commented 6 years ago

ok I reverted my bundle copy to master and it looks good. ty!

The-Compiler commented 6 years ago

FWIW I also opened https://github.com/dpallot/simple-websocket-server/issues/73 - until that's fixed, you might want to only import the modules you need instead of doing import * (which is regarded bad practice either way).