20 Commits
3.1.2 ... 3.2.2

Author SHA1 Message Date
Florian Mounier
920c435b00 Bump 3.2.2 2017-11-23 14:57:08 +01:00
Florian Mounier
27e6aa8a5d Update changelog 2017-11-23 14:56:56 +01:00
Florian Mounier
92633f52ce Fix unescaping entities when linkifying 2017-11-23 14:56:18 +01:00
Florian Mounier
f5f854964b Bump 3.2.1 2017-09-27 11:55:15 +02:00
Florian Mounier
55528fdf91 Issue correct X.509 v3 certificates (you will need to re-generate your certs) 2017-09-27 11:54:58 +02:00
Florian Mounier
9eae13486e Use X509 v4. 2017-09-27 11:34:41 +02:00
Florian Mounier
79bd074dae Bump 3.2.0 2017-09-27 10:59:19 +02:00
Mounier Florian
7b0ba2bfe7 Merge pull request #147 from 3ch01c/master
updated cert generation to v3 to comply with new browser standards
2017-09-21 17:58:55 +02:00
Mounier Florian
db17b9d8ac Merge pull request #152 from f0ma/master
Fix problem with ignoring --shell option in python2
2017-09-21 17:58:11 +02:00
Stanislav Ivanov
b5de82bfcf Fix problem with ignoring --shell option in python2 2017-09-21 18:04:03 +03:00
Jack Miner
13dbe0434c updated cert generation to v3 to comply with new browser standards 2017-07-24 17:52:14 -06:00
Florian Mounier
ef0057c23f Bump 3.1.5 2017-05-29 10:32:28 +02:00
Mounier Florian
6bc8e1438f Merge pull request #146 from warpkwd/fix_i_dont_options
fix i-hereby-...-whatsoever option
2017-05-29 10:21:39 +02:00
Yukihiro KAWADA
8856ea9dc4 fix i-hereby-...-whatsoever option
i-hereby-...-whatsoever revise to i_hereby_whatsoever
2017-05-24 12:59:18 +09:00
Florian Mounier
4edb2d269f Bump 3.1.4 2017-05-15 15:32:50 +02:00
Florian Mounier
272891470c Add --i-hereby-declare-i-dont-want-any-security-whatsoever option. Fix #143 2017-05-15 15:32:39 +02:00
Florian Mounier
574b3dc74b Bump 3.1.3 2017-05-15 11:31:07 +02:00
Florian Mounier
269dd2b618 Fix crash on lsof on python3 2017-05-15 11:30:59 +02:00
Florian Mounier
0625e05cbb Actually fix white-space on folded lines. 2017-05-10 16:01:40 +02:00
Florian Mounier
6b1101bc45 Fix white-space on folded lines. 2017-05-10 15:59:42 +02:00
15 changed files with 132 additions and 36 deletions

2
.gitignore vendored
View File

@@ -9,4 +9,4 @@ sass/scss
*.egg-info/
build/
.cache/
.env/
.env*

View File

@@ -1,3 +1,28 @@
3.2.2
=====
* Fix unescaping entities when linkifying
3.2.1
=====
* Issue correct X.509 v3 certificates (you will need to re-generate your certs)
3.1.5
=====
* Fix new option in older tornado version. (#146 thanks @warpkwd)
3.1.4
=====
* Add --i-hereby-declare-i-dont-want-any-security-whatsoever option (#143)
3.1.3
=====
* Fix lsof parsing crash on python 2
3.1.0
=====

View File

@@ -4,7 +4,7 @@ include Makefile.config
all: install lint check-outdated run-debug
install:
test -d $(VENV) || virtualenv $(VENV)
test -d $(VENV) || virtualenv $(VENV) -p $(PYTHON_VERSION)
$(PIP) install --upgrade --no-cache pip setuptools -e .[lint] devcore
$(NPM) install
@@ -20,9 +20,10 @@ lint:
check-outdated:
$(PIP) list --outdated --format=columns
ARGS ?= --port=1212 --unsecure --debug
run-debug:
sleep 0.5 && $(BROWSER) http://localhost:1212&
$(PYTHON) ./butterfly.server.py --port=1212 --unsecure --debug
$(PYTHON) ./butterfly.server.py $(ARGS)
build-coffee:
$(NODE_MODULES)/.bin/grunt

View File

@@ -1,7 +1,8 @@
PROJECT_NAME = butterfly
# Python env
VENV = $(PWD)/.env
PYTHON_VERSION ?= python
VENV = $(PWD)/.env$(if $(filter $(PYTHON_VERSION),python),,-$(PYTHON_VERSION))
PIP = $(VENV)/bin/pip
PYTHON = $(VENV)/bin/python
PYTEST = $(VENV)/bin/py.test

View File

@@ -45,7 +45,8 @@ tornado.options.define("unminified", default=False,
tornado.options.define("host", default='localhost', help="Server host")
tornado.options.define("port", default=57575, type=int, help="Server port")
tornado.options.define("keepalive_interval", default=30, type=int,
help="Interval between ping packets sent from server to client (in seconds)")
help="Interval between ping packets sent from server "
"to client (in seconds)")
tornado.options.define("one_shot", default=False,
help="Run a one-shot instance. Quit at term close")
tornado.options.define("shell", help="Shell to execute at login")
@@ -54,10 +55,18 @@ tornado.options.define("cmd",
help="Command to run instead of shell, f.i.: 'ls -l'")
tornado.options.define("unsecure", default=False,
help="Don't use ssl not recommended")
tornado.options.define("i_hereby_declare_i_dont_want_any_security_whatsoever",
default=False,
help="Remove all security and warnings. There are some "
"use cases for that. Use this if you really know what "
"you are doing.")
tornado.options.define("login", default=False,
help="Use login screen at start")
tornado.options.define("pam_profile", default="", type=str,
help="When --login=True provided and running as ROOT, use PAM with the specified PAM profile for authentication and then execute the user's default shell. Will override --shell.")
help="When --login=True provided and running as ROOT, "
"use PAM with the specified PAM profile for "
"authentication and then execute the user's default "
"shell. Will override --shell.")
tornado.options.define("force_unicode_width",
default=False,
help="Force all unicode characters to the same width."
@@ -76,6 +85,7 @@ tornado.options.define("uri_root_path", default='',
help="Sets the servier root path: "
"example.com/<uri_root_path>/static/")
if os.getuid() == 0:
ev = os.getenv('XDG_CONFIG_DIRS', '/etc')
else:
@@ -131,6 +141,9 @@ log = logging.getLogger('butterfly')
host = options.host
port = options.port
if options.i_hereby_declare_i_dont_want_any_security_whatsoever:
options.unsecure = True
if not os.path.exists(options.ssl_dir):
os.makedirs(options.ssl_dir)
@@ -165,6 +178,9 @@ def read(file):
with open(file, 'rb') as fd:
return fd.read()
def b(s):
return s.encode('utf-8')
if options.generate_certs:
from OpenSSL import crypto
@@ -175,6 +191,7 @@ if options.generate_certs:
ca_pk = crypto.PKey()
ca_pk.generate_key(crypto.TYPE_RSA, 2048)
ca_cert = crypto.X509()
ca_cert.set_version(2)
ca_cert.get_subject().CN = 'Butterfly CA on %s' % socket.gethostname()
fill_fields(ca_cert.get_subject())
ca_cert.set_serial_number(uuid.uuid4().int)
@@ -182,6 +199,21 @@ if options.generate_certs:
ca_cert.gmtime_adj_notAfter(315360000) # to 10y
ca_cert.set_issuer(ca_cert.get_subject()) # Self signed
ca_cert.set_pubkey(ca_pk)
ca_cert.add_extensions([
crypto.X509Extension(
b('basicConstraints'), True, b('CA:TRUE, pathlen:0')),
crypto.X509Extension(
b('keyUsage'), True, b('keyCertSign, cRLSign')),
crypto.X509Extension(
b('subjectKeyIdentifier'), False, b('hash'), subject=ca_cert),
])
ca_cert.add_extensions([
crypto.X509Extension(
b('authorityKeyIdentifier'), False,
b('issuer:always, keyid:always'),
issuer=ca_cert, subject=ca_cert
)
])
ca_cert.sign(ca_pk, 'sha512')
write(ca, crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert))
@@ -195,12 +227,23 @@ if options.generate_certs:
server_pk = crypto.PKey()
server_pk.generate_key(crypto.TYPE_RSA, 2048)
server_cert = crypto.X509()
server_cert.set_version(2)
server_cert.get_subject().CN = host
alt = 'subjectAltName'
value = 'DNS:%s' % host
server_cert.add_extensions([crypto.X509Extension(
alt.encode('utf-8'), False, value.encode('utf-8'))])
server_cert.add_extensions([
crypto.X509Extension(
b('basicConstraints'), False, b('CA:FALSE')),
crypto.X509Extension(
b('subjectKeyIdentifier'), False, b('hash'), subject=server_cert),
crypto.X509Extension(
b('subjectAltName'), False, b('DNS:%s' % host)),
])
server_cert.add_extensions([
crypto.X509Extension(
b('authorityKeyIdentifier'), False,
b('issuer:always, keyid:always'),
issuer=ca_cert, subject=ca_cert
)
])
fill_fields(server_cert.get_subject())
server_cert.set_serial_number(uuid.uuid4().int)
server_cert.gmtime_adj_notBefore(0) # From now
@@ -250,6 +293,7 @@ if (options.generate_current_user_pkcs or
client_pk.generate_key(crypto.TYPE_RSA, 2048)
client_cert = crypto.X509()
client_cert.set_version(2)
client_cert.get_subject().CN = user
fill_fields(client_cert.get_subject())
client_cert.set_serial_number(uuid.uuid4().int)

View File

@@ -1,5 +1,5 @@
__title__ = "butterfly"
__version__ = "3.1.2"
__version__ = "3.2.2"
__summary__ = "A sleek web based terminal emulator"
__uri__ = "https://github.com/paradoxxxzero/butterfly"

View File

@@ -51,6 +51,8 @@ body
.extra
display: block
white-space: pre-wrap
word-break: break-all
&::-webkit-scrollbar
background: $scroll-bg

View File

@@ -1,5 +1,5 @@
(function() {
var Popup, Selection, _set_theme_href, _theme, alt, cancel, clean_ansi, copy, ctrl, first, histSize, linkify, maybePack, nextLeaf, packSize, popup, previousLeaf, selection, setAlarm, tid, virtualInput, walk,
var Popup, Selection, _set_theme_href, _theme, alt, cancel, clean_ansi, copy, ctrl, escape, first, histSize, linkify, maybePack, nextLeaf, packSize, popup, previousLeaf, selection, setAlarm, tags, tid, virtualInput, walk,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
clean_ansi = function(data) {
@@ -202,12 +202,25 @@
return text.replace(urlPattern, '<a href="$&">$&</a>').replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>').replace(emailAddressPattern, '<a href="mailto:$&">$&</a>');
};
tags = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;'
};
escape = function(s) {
return s.replace(/[&<>]/g, function(tag) {
return tags[tag] || tag;
});
};
Terminal.on('change', function(line) {
return walk(line, function() {
var linkified, newNode;
var linkified, newNode, val;
if (this.nodeType === 3) {
linkified = linkify(this.nodeValue);
if (linkified !== this.nodeValue) {
val = this.nodeValue;
linkified = linkify(escape(val));
if (linkified !== val) {
newNode = document.createElement('span');
newNode.innerHTML = linkified;
this.parentElement.replaceChild(newNode, this);

File diff suppressed because one or more lines are too long

View File

@@ -2827,7 +2827,9 @@ body {
cursor: zoom-out;
background-color: #09080a; }
body .line.extended.expanded .extra {
display: block; }
display: block;
white-space: pre-wrap;
word-break: break-all; }
body::-webkit-scrollbar {
background: #110f13;
width: 0.75em; }

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
! ! {{ colors.red if opts.unsecure else colors.green }}{{ butterfly.socket.remote_addr }}:{{ butterfly.socket.remote_port }}{{ colors.reset }}
For more information type: {{ colors.white }}$ {{ colors.green }}butterfly help{{ colors.reset }}
{% if opts.unsecure %}{{ colors.light_red + '\x1b[5m' }}/!\{{ colors.reset }} {{ colors.red }}This session is UNSECURE everyone can access you terminal at:
{% if opts.unsecure and not opts.i_hereby_declare_i_dont_want_any_security_whatsoever %}{{ colors.light_red + '\x1b[5m' }}/!\{{ colors.reset }} {{ colors.red }}This session is UNSECURE everyone can access you terminal at:
{{ uri }}
{% else %}You can share your session with the following uri:
{{ uri }}

View File

@@ -196,19 +196,19 @@ class Terminal(object):
tty, os.getpid(),
self.callee.name, self.uri)
if not tornado.options.options.unsecure or (
self.socket.local and
self.caller == self.callee and
server == self.callee
) and not tornado.options.options.login:
local_login = (
self.socket.local and self.caller == self.callee and
server == self.callee)
secure = not tornado.options.options.unsecure
force_login = tornado.options.options.login
ignore_security = (
tornado.options.options.
i_hereby_declare_i_dont_want_any_security_whatsoever)
if not force_login and (ignore_security or secure or local_login):
# User has been auth with ssl or is the same user as server
# or login is explicitly turned off
if (
not tornado.options.options.unsecure and not (
self.socket.local and
self.caller == self.callee and
server == self.callee
)):
if secure and not local_login:
# User is authed by ssl, setting groups
try:
os.initgroups(self.callee.name, self.callee.gid)
@@ -264,7 +264,7 @@ class Terminal(object):
args = ['/bin/su']
args.append('-l')
if sys.platform == 'linux' and tornado.options.options.shell:
if sys.platform.startswith('linux') and tornado.options.options.shell:
args.append('-s')
args.append(tornado.options.options.shell)
args.append(self.callee.name)

View File

@@ -168,7 +168,7 @@ def get_lsof_socket_line(addr, port):
# May want to make this into a dictionary in the future...
regex = "\w+\s+(?P<pid>\d+)\s+(?P<user>\w+).*\s" \
"(?P<laddr>.*?):(?P<lport>\d+)->(?P<raddr>.*?):(?P<rport>\d+)"
output = subprocess.check_output(['lsof', '-Pni'])
output = subprocess.check_output(['lsof', '-Pni']).decode('utf-8')
lines = output.split('\n')
for line in lines:
# Look for local address with peer port

View File

@@ -14,11 +14,19 @@ linkify = (text) ->
.replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>')
.replace(emailAddressPattern, '<a href="mailto:$&">$&</a>')
tags =
'&': '&amp;'
'<': '&lt;'
'>': '&gt;'
escape = (s) -> s.replace(/[&<>]/g, (tag) -> tags[tag] or tag)
Terminal.on 'change', (line) ->
walk line, ->
if @nodeType is 3
linkified = linkify @nodeValue
if linkified isnt @nodeValue
val = @nodeValue
linkified = linkify escape(val)
if linkified isnt val
newNode = document.createElement('span')
newNode.innerHTML = linkified
@parentElement.replaceChild newNode, @