Starting to rename the project to Passageway
This commit is contained in:
parent
e15cb9e96a
commit
d29120136e
|
@ -1,3 +1,17 @@
|
|||
.idea
|
||||
.idea/*
|
||||
.idea/**/*
|
||||
*.gem
|
||||
*.rbc
|
||||
.bundle
|
||||
.config
|
||||
.yardoc
|
||||
Gemfile.lock
|
||||
InstalledFiles
|
||||
_yardoc
|
||||
coverage
|
||||
doc/
|
||||
lib/bundler/man
|
||||
pkg
|
||||
rdoc
|
||||
spec/reports
|
||||
test/tmp
|
||||
test/version_tmp
|
||||
tmp
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in passageway.gemspec
|
||||
gemspec
|
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2013 R. Tyler Croy
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
6
Manifest
6
Manifest
|
@ -1,6 +0,0 @@
|
|||
Rakefile
|
||||
lib/localtunnel.rb
|
||||
lib/localtunnel/tunnel.rb
|
||||
lib/localtunnel/net_ssh_gateway_patch.rb
|
||||
bin/localtunnel
|
||||
Manifest
|
|
@ -0,0 +1,29 @@
|
|||
# Passageway
|
||||
|
||||
TODO: Write a gem description
|
||||
|
||||
## Installation
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
gem 'passageway'
|
||||
|
||||
And then execute:
|
||||
|
||||
$ bundle
|
||||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install passageway
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Write usage instructions here
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork it
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||
4. Push to the branch (`git push origin my-new-feature`)
|
||||
5. Create new Pull Request
|
65
README.rdoc
65
README.rdoc
|
@ -1,65 +0,0 @@
|
|||
= localtunnel -- instant public tunnel to your local web server
|
||||
|
||||
== Install
|
||||
|
||||
To get the dependencies if you don't have them, type:
|
||||
|
||||
sudo apt-get install ruby ruby1.8-dev rubygems1.8 libopenssl-ruby
|
||||
|
||||
Now you can install localtunnel with RubyGems:
|
||||
|
||||
sudo gem install localtunnel
|
||||
|
||||
or to get the source:
|
||||
|
||||
git clone http://github.com/progrium/localtunnel.git
|
||||
|
||||
== Usage
|
||||
|
||||
localtunnel [options] <localport>
|
||||
-k, --key FILE upload a public key for authentication
|
||||
|
||||
Localtunnel is a client to a free and open source reverse tunneling
|
||||
service made specifically for web traffic. It's intended to be used to
|
||||
temporarily expose local web servers to the greater Internet for
|
||||
debugging, unit tests, demos, etc.
|
||||
|
||||
This is how you make your local port 8080 public:
|
||||
|
||||
$ localtunnel 8080
|
||||
Port 8080 is now publicly accessible from http://8bv2.localtunnel.com ...
|
||||
|
||||
Using localtunnel is comparable to using SSH reverse/remote port
|
||||
forwarding on a remote host that has GatewayPorts enabled, but without
|
||||
all the configuration or the need of a host. The localtunnel command
|
||||
works with a server component that is running on localtunnel.com,
|
||||
which is provided as a free service.
|
||||
|
||||
If you have never run localtunnel before, you'll need to upload a public
|
||||
key to authenticate. You do this once:
|
||||
|
||||
$ localtunnel -k ~/.ssh/id_rsa.pub 8080
|
||||
|
||||
After that, you shouldn't have to use -k again.
|
||||
|
||||
Localtunnel can be started before or after the local web server. It
|
||||
tunnels through to the url given in that status message "publicly
|
||||
accessible from..." for as long as the command is running. The tunnel
|
||||
is closed if the command exits.
|
||||
|
||||
Localtunnel will search for the file .localtunnel_callback in the CWD.
|
||||
If it exists, it will execute the file with one argument, the public
|
||||
endpoint, when the tunnel is opened. This is useful for starting other
|
||||
tools or processes that need the name of the endpoint.
|
||||
|
||||
== Contributors
|
||||
|
||||
andyl (andy@r210.com)
|
||||
Charles Merriam (charles.merriam@gmail.com)
|
||||
Hunter Gillane (hunter.gillane@gmail.com)
|
||||
Michael Sofaer (msofaer@pivotallabs.com)
|
||||
Jeff Lindsay (progrium@gmail.com)
|
||||
|
||||
== License
|
||||
|
||||
MIT
|
17
Rakefile
17
Rakefile
|
@ -1,16 +1 @@
|
|||
require 'rubygems'
|
||||
require 'rake'
|
||||
require 'echoe'
|
||||
|
||||
Echoe.new('localtunnel', '0.3.1') do |p|
|
||||
p.description = "instant public tunnel to your local web server"
|
||||
p.url = "http://github.com/progrium/localtunnel"
|
||||
p.author = "Jeff Lindsay"
|
||||
p.email = "jeff.lindsay@twilio.com"
|
||||
p.rdoc_pattern = //
|
||||
p.rdoc_options = []
|
||||
p.ignore_pattern = ["tmp/*", "script/*"]
|
||||
p.executable_pattern = ["bin/*"]
|
||||
p.runtime_dependencies = ["json >=1.2.4", "net-ssh >=2.0.22", "net-ssh-gateway >=1.0.1"]
|
||||
p.development_dependencies = []
|
||||
end
|
||||
require "bundler/gem_tasks"
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
$: << File.expand_path(File.dirname(__FILE__))
|
||||
require 'localtunnel/tunnel'
|
|
@ -0,0 +1,5 @@
|
|||
require "passageway/version"
|
||||
|
||||
module Passageway
|
||||
# Your code goes here...
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
module Passageway
|
||||
VERSION = "0.0.1"
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'passageway/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "passageway"
|
||||
spec.version = Passageway::VERSION
|
||||
spec.authors = ["R. Tyler Croy"]
|
||||
spec.email = ["tyler@monkeypox.org"]
|
||||
spec.description = %q{TODO: Write a gem description}
|
||||
spec.summary = %q{TODO: Write a gem summary}
|
||||
spec.homepage = ""
|
||||
spec.license = "MIT"
|
||||
|
||||
spec.files = `git ls-files`.split($/)
|
||||
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.3"
|
||||
spec.add_development_dependency "rake"
|
||||
end
|
106
server.py
106
server.py
|
@ -1,106 +0,0 @@
|
|||
try:
|
||||
from twisted.internet import pollreactor
|
||||
pollreactor.install()
|
||||
except: pass
|
||||
from twisted.internet import protocol, reactor, defer, task
|
||||
from twisted.web import http, proxy, resource, server
|
||||
from twisted.python import log
|
||||
import sys, time
|
||||
import urlparse
|
||||
import socket
|
||||
import simplejson
|
||||
import re
|
||||
|
||||
SSH_USER = 'localtunnel'
|
||||
AUTHORIZED_KEYS = '/home/localtunnel/.ssh/authorized_keys'
|
||||
PORT_RANGE = [32000, 64000]
|
||||
BANNER = "This localtunnel service is brought to you by Twilio."
|
||||
SSH_OPTIONS = 'command="/bin/echo Shell access denied",no-agent-forwarding,no-pty,no-user-rc,no-X11-forwarding '
|
||||
KEY_REGEX = re.compile(r'^ssh-(\w{3}) [^\n]+$')
|
||||
|
||||
def port_available(port):
|
||||
try:
|
||||
socket.create_connection(['127.0.0.1', port]).close()
|
||||
return False
|
||||
except socket.error:
|
||||
return True
|
||||
|
||||
def baseN(num,b=32,numerals="23456789abcdefghijkmnpqrstuvwxyz"):
|
||||
return ((num == 0) and "0" ) or (baseN(num // b, b).lstrip("0") + numerals[num % b])
|
||||
|
||||
class LocalTunnelReverseProxy(proxy.ReverseProxyResource):
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self, user, host='127.0.0.1'):
|
||||
self.user = user
|
||||
self.tunnels = {}
|
||||
proxy.ReverseProxyResource.__init__(self, host, None, None)
|
||||
|
||||
def find_tunnel_name(self):
|
||||
name = baseN(abs(hash(time.time())))[0:4]
|
||||
if (name in self.tunnels and not port_available(self.tunnels[name])) or name == 'open':
|
||||
time.sleep(0.1)
|
||||
return self.find_tunnel_name()
|
||||
return name
|
||||
|
||||
def find_tunnel_port(self):
|
||||
port = PORT_RANGE[0]
|
||||
start_time = time.time()
|
||||
while not port_available(port):
|
||||
if time.time()-start_time > 3:
|
||||
raise Exception("No port available")
|
||||
port += 1
|
||||
if port >= PORT_RANGE[1]: port = PORT_RANGE[0]
|
||||
return port
|
||||
|
||||
def garbage_collect(self):
|
||||
for name in self.tunnels:
|
||||
if port_available(self.tunnels[name]):
|
||||
del self.tunnels[name]
|
||||
|
||||
def install_key(self, key):
|
||||
if not KEY_REGEX.match(key.strip()):
|
||||
return False
|
||||
key = ''.join([SSH_OPTIONS, key.strip(), "\n"])
|
||||
fr = open(AUTHORIZED_KEYS, 'r')
|
||||
if not key in fr.readlines():
|
||||
fa = open(AUTHORIZED_KEYS, 'a')
|
||||
fa.write(key)
|
||||
fa.close()
|
||||
fr.close()
|
||||
return True
|
||||
|
||||
def register_tunnel(self, superhost, key=None):
|
||||
if key and not self.install_key(key): return simplejson.dumps(dict(error="Invalid key."))
|
||||
name = self.find_tunnel_name()
|
||||
port = self.find_tunnel_port()
|
||||
self.tunnels[name] = port
|
||||
return simplejson.dumps(
|
||||
dict(through_port=port, user=self.user, host='%s.%s' % (name, superhost), banner=BANNER))
|
||||
|
||||
def render(self, request):
|
||||
host = request.getHeader('host')
|
||||
name, superhost = host.split('.', 1)
|
||||
if host.startswith('open.'):
|
||||
request.setHeader('Content-Type', 'application/json')
|
||||
return self.register_tunnel(superhost, request.args.get('key', [None])[0])
|
||||
else:
|
||||
if not name in self.tunnels: return "Not found"
|
||||
|
||||
request.content.seek(0, 0)
|
||||
clientFactory = self.proxyClientFactoryClass(
|
||||
request.method, request.uri, request.clientproto,
|
||||
request.getAllHeaders(), request.content.read(), request)
|
||||
self.reactor.connectTCP(self.host, self.tunnels[name], clientFactory)
|
||||
return server.NOT_DONE_YET
|
||||
|
||||
#if 'location' in request.responseHeaders and host in request.responseHeaders['location']:
|
||||
# # Strip out the port they think they need
|
||||
# p = re.compile(r'%s\:\d+' % host)
|
||||
# location = p.sub(host, request.responseHeaders['location'])
|
||||
# request.responseHeaders['location'] = location
|
||||
|
||||
|
||||
log.startLogging(sys.stdout)
|
||||
reactor.listenTCP(80, server.Site(LocalTunnelReverseProxy(SSH_USER)))
|
||||
reactor.run()
|
Loading…
Reference in New Issue