mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-26 07:08:08 +00:00
This commit is contained in:
13
bin/bopen
Executable file
13
bin/bopen
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import webbrowser
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Butterfly tab opener.')
|
||||
parser.add_argument(
|
||||
'location',
|
||||
default=os.getcwd(),
|
||||
help='Directory to open the new tab in. (Defaults to current)')
|
||||
args = parser.parse_args()
|
||||
|
||||
webbrowser.open('%swd%s' % (os.getenv('LOCATION'), args.location))
|
||||
@@ -1,9 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
from butterfly.escapes import image
|
||||
from butterfly.utils import ansi_colors
|
||||
import os
|
||||
import base64
|
||||
|
||||
print("Welcome to the butterfly help.")
|
||||
print(ansi_colors.white + "Welcome to the butterfly help." + ansi_colors.reset)
|
||||
with image('image/png'):
|
||||
with open(
|
||||
os.path.join(
|
||||
@@ -13,10 +14,20 @@ with image('image/png'):
|
||||
print("""
|
||||
Butterfly is a xterm compliant terminal built with python and javascript.
|
||||
|
||||
Terminal functionalities:
|
||||
[Alt] + [a] : Set an alarm which sends a notification when a modification is detected.
|
||||
[Ctrl] + [Shift] + [Up] : Trigger visual selection mode. Hitting [Enter] inserts the selection in the prompt.
|
||||
[ScrollLock] : Lock the scrolling to the current position. Press again to release.
|
||||
[Alt] + [z] : Escape: don't catch the next pressed key. Useful for using native search for example. ([Alt] + [z] then [Ctrl] + [f]).
|
||||
[Ctrl] + [c] <<hold>> : Cut the output when [Ctrl] + [c] is not enough.
|
||||
""")
|
||||
{title}Terminal functionalities:{reset}
|
||||
{strong}[Alt] + [a] : {reset}Set an alarm which sends a notification when a modification is detected.
|
||||
{strong}[Ctrl] + [Shift] + [Up] : {reset}Trigger visual selection mode. Hitting [Enter] inserts the selection in the prompt.
|
||||
{strong}[ScrollLock] : {reset}Lock the scrolling to the current position. Press again to release.
|
||||
{strong}[Alt] + [z] : {reset}Escape: don't catch the next pressed key. Useful for using native search for example. ([Alt] + [z] then [Ctrl] + [f]).
|
||||
{strong}[Ctrl] + [c] <<hold>> : {reset}Cut the output when [Ctrl] + [c] is not enough.
|
||||
|
||||
{title}Butterfly programs:{reset}
|
||||
{strong}bcat : {reset}A wrapper around cat allowing to display images as <img> instead of binary.
|
||||
{strong}bopen : {reset}Open a new terminal at specified location.
|
||||
{strong}b16M : {reset}Test the 16M colors support in terminal.
|
||||
{strong}bhr : {reset}Put a html hr. This is a test and needs --allow-html-escapes flag.
|
||||
{strong}bcal : {reset}Display current month using html. This is a test and needs --allow-html-escapes flag.
|
||||
""".format(
|
||||
title=ansi_colors.light_blue,
|
||||
strong=ansi_colors.white,
|
||||
reset=ansi_colors.reset))
|
||||
|
||||
4
bin/nt
4
bin/nt
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import webbrowser
|
||||
webbrowser.open('%swd%s' % (os.getenv('LOCATION'), os.getcwd()))
|
||||
@@ -36,6 +36,7 @@ tornado.options.define("more", 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("shell", help="Shell to execute at login")
|
||||
tornado.options.define("motd", default='motd', help="Path to the motd file.")
|
||||
tornado.options.define("cmd",
|
||||
help="Command to run instead of shell, f.i.: 'ls -l'")
|
||||
tornado.options.define("unsecure", default=False,
|
||||
|
||||
@@ -49,44 +49,6 @@ def u(s):
|
||||
return s
|
||||
|
||||
|
||||
def motd(socket):
|
||||
return (
|
||||
'''
|
||||
B ` '
|
||||
;,,, ` ' ,,,;
|
||||
`Y888888bo. : : .od888888Y'
|
||||
8888888888b. : : .d8888888888
|
||||
88888Y' `Y8b. ` ' .d8Y' `Y88888
|
||||
j88888 R.db.B Yb. ' ' .dY R.db.B 88888k
|
||||
`888 RY88YB `b ( ) d' RY88YB 888'
|
||||
888b R'"B ,', R"'B d888
|
||||
j888888bd8gf"' ':' `"?g8bd888888k
|
||||
R'Y'B .8' d' 'b '8. R'Y'X
|
||||
R!B .8' RdbB d'; ;`b RdbB '8. R!B
|
||||
d88 R`'B 8 ; ; 8 R`'B 88b Rbutterfly Zv %sB
|
||||
d888b .g8 ',' 8g. d888b
|
||||
:888888888Y' 'Y888888888: AConnecting to:B
|
||||
'! 8888888' `8888888 !' G%sB
|
||||
'8Y R`Y Y'B Y8'
|
||||
R Y Y AFrom:R
|
||||
! ! G%sX
|
||||
|
||||
For more information type: $ butterfly_help
|
||||
|
||||
'''
|
||||
.replace('G', '\x1b[3%d;1m' % (
|
||||
1 if tornado.options.options.unsecure else 2))
|
||||
.replace('B', '\x1b[34;1m')
|
||||
.replace('R', '\x1b[37;1m')
|
||||
.replace('Z', '\x1b[33;1m')
|
||||
.replace('A', '\x1b[37;0m')
|
||||
.replace('X', '\x1b[0m')
|
||||
.replace('\n', '\r\n')
|
||||
% (__version__,
|
||||
'%s:%d' % (socket.local_addr, socket.local_port),
|
||||
'%s:%d' % (socket.remote_addr, socket.remote_port)))
|
||||
|
||||
|
||||
@url(r'/(?:user/(.+))?/?(?:wd/(.+))?')
|
||||
class Index(Route):
|
||||
def get(self, user, path):
|
||||
@@ -260,6 +222,7 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
|
||||
def open(self, user, path):
|
||||
self.fd = None
|
||||
self.closed = False
|
||||
if self.request.headers['Origin'] not in (
|
||||
'http://%s' % self.request.headers['Host'],
|
||||
'https://%s' % self.request.headers['Host']):
|
||||
@@ -304,7 +267,16 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
|
||||
TermWebSocket.terminals.add(self)
|
||||
|
||||
self.write_message(motd(self.socket))
|
||||
motd = (self.render_string(
|
||||
tornado.options.options.motd,
|
||||
butterfly=self,
|
||||
version=__version__,
|
||||
opts=tornado.options.options,
|
||||
colors=utils.ansi_colors)
|
||||
.decode('utf-8')
|
||||
.replace('\r', '')
|
||||
.replace('\n', '\r\n'))
|
||||
self.write_message(motd)
|
||||
self.pty()
|
||||
|
||||
def on_message(self, message):
|
||||
@@ -318,7 +290,7 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
fcntl.ioctl(self.fd, termios.TIOCSWINSZ, s)
|
||||
self.log.info('SIZE (%d, %d)' % (cols, rows))
|
||||
elif message[0] == 'S':
|
||||
self.log.info('WRIT<%r' % message)
|
||||
self.log.debug('WRIT<%r' % message)
|
||||
self.writer.write(message[1:])
|
||||
self.writer.flush()
|
||||
|
||||
@@ -329,7 +301,7 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
except IOError:
|
||||
read = ''
|
||||
|
||||
self.log.info('READ>%r' % read)
|
||||
self.log.debug('READ>%r' % read)
|
||||
if read and len(read) != 0 and self.ws_connection:
|
||||
self.write_message(read.decode('utf-8', 'replace'))
|
||||
else:
|
||||
@@ -338,10 +310,13 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
if events & ioloop.ERROR:
|
||||
self.log.info('Error on fd %d, closing' % fd)
|
||||
# Terminated
|
||||
self.on_close()
|
||||
self.close()
|
||||
|
||||
def on_close(self):
|
||||
utils.rm_user_info(self.fd, self.pid, self.callee.name)
|
||||
if self.closed:
|
||||
return
|
||||
self.closed = True
|
||||
if self.fd is not None:
|
||||
self.log.info('Closing fd %d' % self.fd)
|
||||
|
||||
@@ -349,6 +324,8 @@ class TermWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
self.log.info('pid is 0')
|
||||
return
|
||||
|
||||
utils.rm_user_info(self.fd, self.pid, self.callee.name)
|
||||
|
||||
try:
|
||||
ioloop.remove_handler(self.fd)
|
||||
except Exception:
|
||||
|
||||
22
butterfly/templates/motd
Normal file
22
butterfly/templates/motd
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
{{ colors.blue }} ` '
|
||||
;,,, ` ' ,,,;
|
||||
`Y888888bo. : : .od888888Y'
|
||||
8888888888b. : : .d8888888888
|
||||
88888Y' `Y8b. ` ' .d8Y' `Y88888
|
||||
j88888 {{ colors.white }}.db.{{ colors.blue }} Yb. ' ' .dY {{ colors.white }}.db.{{ colors.blue }} 88888k
|
||||
`888 {{ colors.white }}Y88Y{{ colors.blue }} `b ( ) d' {{ colors.white }}Y88Y{{ colors.blue }} 888'
|
||||
888b {{ colors.white }}'"{{ colors.blue }} ,', {{ colors.white }}"'{{ colors.blue }} d888
|
||||
j888888bd8gf"' ':' `"?g8bd888888k
|
||||
{{ colors.white }}'Y'{{ colors.blue }} .8' d' 'b '8. {{ colors.white }}'Y'{{ colors.reset }}
|
||||
{{ colors.white }}!{{ colors.blue }} .8' {{ colors.white }}db{{ colors.blue }} d'; ;`b {{ colors.white }}db{{ colors.blue }} '8. {{ colors.white }}!{{ colors.blue }}
|
||||
d88 {{ colors.white }}`'{{ colors.blue }} 8 ; ; 8 {{ colors.white }}`'{{ colors.blue }} 88b {{ colors.white }}butterfly {{ colors.yellow }}v {{ version }}{{ colors.blue }}
|
||||
d888b .g8 ',' 8g. d888b
|
||||
:888888888Y' 'Y888888888: {{ colors.light_white }}Connecting to:{{ colors.blue }}
|
||||
'! 8888888' `8888888 !' {{ colors.red if opts.unsecure else colors.green }}{{ butterfly.socket.local_addr }}:{{ butterfly.socket.local_port }}{{ colors.blue }}
|
||||
'8Y {{ colors.white }}`Y Y'{{ colors.blue }} Y8'
|
||||
{{ colors.white }} Y Y {{ colors.light_white }}From:{{ colors.white }}
|
||||
! ! {{ colors.red if opts.unsecure else colors.green }}{{ butterfly.socket.remote_addr }}:{{ butterfly.socket.remote_port }}{{ colors.reset }}
|
||||
|
||||
For more information type: $ butterfly_help
|
||||
|
||||
@@ -290,6 +290,10 @@ def utmp_line(type, pid, fd, user, host, ts):
|
||||
|
||||
|
||||
def add_user_info(fd, pid, user, host):
|
||||
# Freebsd format is not yet supported.
|
||||
# Please submit PR
|
||||
if sys.platform != 'linux':
|
||||
return
|
||||
utmp = utmp_line(7, pid, fd, user, host, time.time())
|
||||
for kind, file in {
|
||||
'utmp': get_utmp_file(),
|
||||
@@ -310,10 +314,12 @@ def add_user_info(fd, pid, user, host):
|
||||
else:
|
||||
f.write(utmp_struct.pack(*utmp))
|
||||
except Exception:
|
||||
log.warning('Unable to write utmp info to ' + file, exc_info=True)
|
||||
log.info('Unable to write utmp info to ' + file, exc_info=True)
|
||||
|
||||
|
||||
def rm_user_info(fd, pid, user):
|
||||
if sys.platform != 'linux':
|
||||
return
|
||||
utmp = utmp_line(8, pid, fd, user, '', time.time())
|
||||
for kind, file in {
|
||||
'utmp': get_utmp_file(),
|
||||
@@ -335,4 +341,32 @@ def rm_user_info(fd, pid, user):
|
||||
f.write(utmp_struct.pack(*utmp))
|
||||
|
||||
except Exception:
|
||||
log.warning('Unable to update utmp info to ' + file, exc_info=True)
|
||||
log.info('Unable to update utmp info to ' + file, exc_info=True)
|
||||
|
||||
|
||||
class AnsiColors(object):
|
||||
colors = {
|
||||
'black': 30,
|
||||
'red': 31,
|
||||
'green': 32,
|
||||
'yellow': 33,
|
||||
'blue': 34,
|
||||
'magenta': 35,
|
||||
'cyan': 36,
|
||||
'white': 37
|
||||
}
|
||||
|
||||
def __getattr__(self, key):
|
||||
bold = True
|
||||
if key.startswith('light_'):
|
||||
bold = False
|
||||
key = key[len('light_'):]
|
||||
if key in self.colors:
|
||||
return '\x1b[%d%sm' % (
|
||||
self.colors[key],
|
||||
';1' if bold else '')
|
||||
if key == 'reset':
|
||||
return '\x1b[0m'
|
||||
return ''
|
||||
|
||||
ansi_colors = AnsiColors()
|
||||
|
||||
Reference in New Issue
Block a user