bashhub 3.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bashhub/__init__.py +0 -0
- bashhub/bashhub.py +240 -0
- bashhub/bashhub_globals.py +83 -0
- bashhub/bashhub_setup.py +237 -0
- bashhub/bh.py +125 -0
- bashhub/i_search.py +157 -0
- bashhub/interactive_search.py +120 -0
- bashhub/model/__init__.py +6 -0
- bashhub/model/command.py +55 -0
- bashhub/model/command_form.py +15 -0
- bashhub/model/min_command.py +13 -0
- bashhub/model/serializable.py +47 -0
- bashhub/model/status_view.py +15 -0
- bashhub/model/system.py +42 -0
- bashhub/rest_client.py +251 -0
- bashhub/shell/bashhub.fish +105 -0
- bashhub/shell/bashhub.sh +73 -0
- bashhub/shell/bashhub.zsh +65 -0
- bashhub/shell/deps/bash-preexec.sh +341 -0
- bashhub/shell/deps/lib-bashhub.sh +161 -0
- bashhub/shell_utils.py +17 -0
- bashhub/version.py +5 -0
- bashhub/view/__init__.py +0 -0
- bashhub/view/status.py +25 -0
- bashhub-3.0.2.dist-info/METADATA +203 -0
- bashhub-3.0.2.dist-info/RECORD +30 -0
- bashhub-3.0.2.dist-info/WHEEL +5 -0
- bashhub-3.0.2.dist-info/entry_points.txt +3 -0
- bashhub-3.0.2.dist-info/licenses/LICENSE.md +190 -0
- bashhub-3.0.2.dist-info/top_level.txt +1 -0
bashhub/__init__.py
ADDED
|
File without changes
|
bashhub/bashhub.py
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
from time import *
|
|
3
|
+
import click
|
|
4
|
+
import traceback
|
|
5
|
+
import dateutil.parser
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import io
|
|
9
|
+
|
|
10
|
+
from .model import CommandForm
|
|
11
|
+
from . import rest_client
|
|
12
|
+
from . import bashhub_setup
|
|
13
|
+
from . import bashhub_globals
|
|
14
|
+
from .bashhub_globals import BH_FILTER, BH_HOME, BH_SAVE_COMMANDS
|
|
15
|
+
from .bashhub_globals import write_to_config_file
|
|
16
|
+
from .version import version_str
|
|
17
|
+
import shutil
|
|
18
|
+
import requests
|
|
19
|
+
import subprocess
|
|
20
|
+
from . import shell_utils
|
|
21
|
+
import re
|
|
22
|
+
from .view.status import *
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def print_version(ctx, param, value):
|
|
27
|
+
if not value or ctx.resilient_parsing:
|
|
28
|
+
return
|
|
29
|
+
click.echo(version_str)
|
|
30
|
+
ctx.exit()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@click.group(context_settings=CONTEXT_SETTINGS)
|
|
37
|
+
@click.option('-V',
|
|
38
|
+
'--version',
|
|
39
|
+
default=False,
|
|
40
|
+
is_flag=True,
|
|
41
|
+
callback=print_version,
|
|
42
|
+
help='Display version',
|
|
43
|
+
expose_value=False,
|
|
44
|
+
is_eager=True)
|
|
45
|
+
def bashhub():
|
|
46
|
+
"""Bashhub command line client"""
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@bashhub.command()
|
|
51
|
+
def version():
|
|
52
|
+
"""Display version"""
|
|
53
|
+
click.echo(version_str)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@bashhub.command()
|
|
57
|
+
@click.option("-g",
|
|
58
|
+
"--global",
|
|
59
|
+
"is_global",
|
|
60
|
+
default=False,
|
|
61
|
+
is_flag=True,
|
|
62
|
+
help="Turn off saving commands for all sessions.")
|
|
63
|
+
def off(is_global):
|
|
64
|
+
"""Turn off saving commands to Bashhub. Applies for this current session."""
|
|
65
|
+
if is_global:
|
|
66
|
+
write_to_config_file('save_commands', 'False')
|
|
67
|
+
else:
|
|
68
|
+
f = io.open(BH_HOME + '/script.bh', 'w+', encoding='utf-8')
|
|
69
|
+
print(str("export BH_SAVE_COMMANDS='False'"), file=f)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@bashhub.command()
|
|
73
|
+
@click.option('-l',
|
|
74
|
+
"--local",
|
|
75
|
+
help="Turn on saving commands for only this session.",
|
|
76
|
+
is_flag=True)
|
|
77
|
+
def on(local):
|
|
78
|
+
"""Turn on saving commands to Bashhub. Applies globally."""
|
|
79
|
+
f = io.open(BH_HOME + '/script.bh', 'w+', encoding='utf-8')
|
|
80
|
+
|
|
81
|
+
if local:
|
|
82
|
+
print(str("export BH_SAVE_COMMANDS='True'"), file=f)
|
|
83
|
+
else:
|
|
84
|
+
print(str("unset BH_SAVE_COMMANDS"), file=f)
|
|
85
|
+
write_to_config_file('save_commands', 'True')
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@bashhub.command()
|
|
89
|
+
@click.argument('command', type=str)
|
|
90
|
+
@click.argument('path', type=click.Path(exists=True))
|
|
91
|
+
@click.argument('pid', type=int)
|
|
92
|
+
@click.argument('process_start_time', type=int)
|
|
93
|
+
@click.argument('exit_status', type=int)
|
|
94
|
+
def save(command, path, pid, process_start_time, exit_status):
|
|
95
|
+
"""Save a command to Bashhub"""
|
|
96
|
+
pid_start_time = unix_time_to_epoc_millis(process_start_time)
|
|
97
|
+
command = command.strip()
|
|
98
|
+
|
|
99
|
+
# Check if we have commands saving turned on
|
|
100
|
+
if not bashhub_globals.BH_SAVE_COMMANDS:
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
# Check if we should ignore this command.
|
|
104
|
+
if "#ignore" in command:
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
# Check if we should filter this command.
|
|
108
|
+
bh_filter = bashhub_globals.BH_FILTER
|
|
109
|
+
if bh_filter and re.findall(bh_filter, command):
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
# Check that we have an auth token.
|
|
113
|
+
if bashhub_globals.BH_AUTH() == "":
|
|
114
|
+
print("No auth token found. Run 'bashhub setup' to login.")
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
command = CommandForm(command, path, exit_status, pid, pid_start_time)
|
|
118
|
+
rest_client.save_command(command)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@bashhub.command()
|
|
122
|
+
def setup():
|
|
123
|
+
"""Run Bashhub user and system setup"""
|
|
124
|
+
bashhub_setup.main()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@bashhub.command()
|
|
128
|
+
def status():
|
|
129
|
+
"""Stats for this session and user"""
|
|
130
|
+
# Get our user and session information from our context
|
|
131
|
+
(ppid, start_time) = shell_utils.get_session_information()
|
|
132
|
+
status_view = rest_client.get_status_view(ppid, start_time)
|
|
133
|
+
if status_view:
|
|
134
|
+
click.echo(build_status_view(status_view))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@bashhub.command()
|
|
138
|
+
@click.pass_context
|
|
139
|
+
def help(ctx):
|
|
140
|
+
"""Show this message and exit"""
|
|
141
|
+
click.echo(ctx.parent.get_help())
|
|
142
|
+
|
|
143
|
+
# Dynamic help text containing the BH_FILTER variable.
|
|
144
|
+
filtered_text = "BH_FILTER={0}".format(
|
|
145
|
+
BH_FILTER) if BH_FILTER else "BH_FILTER \
|
|
146
|
+
is unset."
|
|
147
|
+
|
|
148
|
+
filter_help_text = """Check if a command is filtered from bashhub. Filtering
|
|
149
|
+
is configured via a regex exported as BH_FILTER.
|
|
150
|
+
\n
|
|
151
|
+
{0}""".format(filtered_text)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@bashhub.command(help=filter_help_text)
|
|
155
|
+
@click.argument('command', type=str)
|
|
156
|
+
@click.option('-r',
|
|
157
|
+
'--regex',
|
|
158
|
+
default=BH_FILTER,
|
|
159
|
+
help='Regex to filter against')
|
|
160
|
+
def filter(command, regex):
|
|
161
|
+
|
|
162
|
+
# Check if the regex we receive is valid
|
|
163
|
+
if not bashhub_globals.is_valid_regex(regex):
|
|
164
|
+
click.secho("Regex {0} is invalid".format(regex), fg='red')
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
v = re.findall(regex, command)
|
|
168
|
+
click.echo(filtered_text)
|
|
169
|
+
if v and regex:
|
|
170
|
+
matched = [str(s) for s in set(v)]
|
|
171
|
+
output = click.style("{0} \nIs Filtered. Matched ".format(command),
|
|
172
|
+
fg='yellow') + click.style(
|
|
173
|
+
str(matched), fg='red')
|
|
174
|
+
click.echo(output)
|
|
175
|
+
else:
|
|
176
|
+
click.echo("{0} \nIs Unfiltered".format(command))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@bashhub.command()
|
|
180
|
+
@click.argument('version', type=str, default='')
|
|
181
|
+
def update(version):
|
|
182
|
+
"""Update your Bashhub installation"""
|
|
183
|
+
|
|
184
|
+
if version != '':
|
|
185
|
+
github = "https://github.com/rcaloras/bashhub-client/archive/{0}.tar.gz".format(
|
|
186
|
+
version)
|
|
187
|
+
response = requests.get(github)
|
|
188
|
+
if response.status_code != 200:
|
|
189
|
+
click.echo("Invalid version number {0}".format(version))
|
|
190
|
+
sys.exit(1)
|
|
191
|
+
|
|
192
|
+
query_param = '?version={0}'.format(version) if version else ''
|
|
193
|
+
url = 'https://bashhub.com/setup' + query_param
|
|
194
|
+
response = requests.get(url, stream=True)
|
|
195
|
+
filename = 'update-bashhub.sh'
|
|
196
|
+
with open(filename, 'wb') as out_file:
|
|
197
|
+
shutil.copyfileobj(response.raw, out_file)
|
|
198
|
+
|
|
199
|
+
subprocess.call(["bash", "-e", filename, version])
|
|
200
|
+
os.remove(filename)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@bashhub.group()
|
|
204
|
+
def util():
|
|
205
|
+
"""Misc utils used by Bashhub"""
|
|
206
|
+
pass
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@util.command()
|
|
210
|
+
def update_system_info():
|
|
211
|
+
"""Updates system info for Bashhub"""
|
|
212
|
+
result = bashhub_setup.update_system_info()
|
|
213
|
+
# Exit code based on if our update call was successful
|
|
214
|
+
sys.exit(0) if result != None else sys.exit(1)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
@util.command()
|
|
218
|
+
@click.argument('date_string', type=str)
|
|
219
|
+
def parsedate(date_string):
|
|
220
|
+
"""date string to seconds since the unix epoch"""
|
|
221
|
+
try:
|
|
222
|
+
date = dateutil.parser.parse(date_string)
|
|
223
|
+
unix_time = int(mktime(date.timetuple()))
|
|
224
|
+
click.echo(unix_time)
|
|
225
|
+
except Exception as e:
|
|
226
|
+
# Should really log an error here
|
|
227
|
+
click.echo(0)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def unix_time_to_epoc_millis(unix_time):
|
|
231
|
+
return int(unix_time) * 1000
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def main():
|
|
235
|
+
try:
|
|
236
|
+
bashhub()
|
|
237
|
+
except Exception as e:
|
|
238
|
+
formatted = traceback.format_exc(e)
|
|
239
|
+
click.echo("Oops, looks like an exception occured: " + str(e))
|
|
240
|
+
sys.exit(1)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file should be used for declaring any global variables that need to be
|
|
3
|
+
pulled in from environment variables or are just used across multiple files.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import time
|
|
9
|
+
import stat
|
|
10
|
+
|
|
11
|
+
import configparser
|
|
12
|
+
from configparser import NoSectionError, NoOptionError
|
|
13
|
+
|
|
14
|
+
# Current time in milleseconds to use across app.
|
|
15
|
+
current_milli_time = lambda: int(round(time.time() * 1000))
|
|
16
|
+
|
|
17
|
+
BH_HOME = '~/.bashhub' if 'HOME' not in list(os.environ.keys()) \
|
|
18
|
+
else os.environ['HOME'] + '/.bashhub'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def write_to_config_file(section, value):
|
|
22
|
+
exists = os.path.exists(BH_HOME)
|
|
23
|
+
file_path = BH_HOME + '/config'
|
|
24
|
+
permissions = stat.S_IRUSR | stat.S_IWUSR
|
|
25
|
+
if exists:
|
|
26
|
+
config = configparser.ConfigParser()
|
|
27
|
+
config.read(BH_HOME + '/config')
|
|
28
|
+
# Add our section if it doesn't exist
|
|
29
|
+
if not config.has_section("bashhub"):
|
|
30
|
+
config.add_section("bashhub")
|
|
31
|
+
|
|
32
|
+
config.set("bashhub", section, value)
|
|
33
|
+
with open(file_path, 'w') as config_file:
|
|
34
|
+
config.write(config_file)
|
|
35
|
+
os.chmod(file_path, permissions)
|
|
36
|
+
return True
|
|
37
|
+
else:
|
|
38
|
+
print("Couldn't find bashhub home directory. Sorry.")
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_from_config(key, default=''):
|
|
43
|
+
try:
|
|
44
|
+
config = configparser.ConfigParser()
|
|
45
|
+
config.read(BH_HOME + '/config')
|
|
46
|
+
return config.get('bashhub', key)
|
|
47
|
+
except NoSectionError as error:
|
|
48
|
+
return default
|
|
49
|
+
except NoOptionError as error:
|
|
50
|
+
return default
|
|
51
|
+
|
|
52
|
+
# Optional environment variable to configure for development
|
|
53
|
+
# export BH_URL='http://localhost:9000'
|
|
54
|
+
BH_URL = os.getenv('BH_URL', get_from_config('url', 'https://bashhub.com'))
|
|
55
|
+
|
|
56
|
+
BH_SAVE_COMMANDS = os.getenv('BH_SAVE_COMMANDS', \
|
|
57
|
+
get_from_config('save_commands')).lower() in ('true', 'yes', 't', 'on', '')
|
|
58
|
+
|
|
59
|
+
BH_SYSTEM_NAME = get_from_config("system_name")
|
|
60
|
+
|
|
61
|
+
# Check if debug mode is enabled
|
|
62
|
+
BH_DEBUG = os.getenv('BH_DEBUG', get_from_config("debug"))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# Get our token from the environment if one is present
|
|
66
|
+
# otherwise retrieve it from our config. Needs to
|
|
67
|
+
# be a function since we may change our token during setup
|
|
68
|
+
def BH_AUTH():
|
|
69
|
+
return os.getenv('BH_ACCESS_TOKEN', get_from_config("access_token"))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def is_valid_regex(regex):
|
|
73
|
+
try:
|
|
74
|
+
re.compile(regex)
|
|
75
|
+
return True
|
|
76
|
+
except re.error:
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
def get_bh_filter():
|
|
80
|
+
filter = os.getenv('BH_FILTER', get_from_config('filter'))
|
|
81
|
+
return filter if is_valid_regex(filter) else '__invalid__'
|
|
82
|
+
|
|
83
|
+
BH_FILTER = get_bh_filter()
|
bashhub/bashhub_setup.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
from time import *
|
|
3
|
+
import jsonpickle
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
import requests
|
|
7
|
+
import getpass
|
|
8
|
+
import traceback
|
|
9
|
+
import uuid
|
|
10
|
+
import stat
|
|
11
|
+
import socket
|
|
12
|
+
from . import rest_client
|
|
13
|
+
from .version import __version__
|
|
14
|
+
from .model import *
|
|
15
|
+
from .bashhub_globals import *
|
|
16
|
+
import requests
|
|
17
|
+
from requests import ConnectionError
|
|
18
|
+
from requests import HTTPError
|
|
19
|
+
import collections
|
|
20
|
+
import configparser
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def query_yes_no(question, default="yes"):
|
|
24
|
+
"""Ask a yes/no question via input() and return their answer.
|
|
25
|
+
|
|
26
|
+
"question" is a string that is presented to the user.
|
|
27
|
+
"default" is the presumed answer if the user just hits <Enter>.
|
|
28
|
+
It must be "yes" (the default), "no" or None (meaning
|
|
29
|
+
an answer is required of the user).
|
|
30
|
+
|
|
31
|
+
The "answer" return value is one of "yes" or "no".
|
|
32
|
+
"""
|
|
33
|
+
valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
|
|
34
|
+
if default == None:
|
|
35
|
+
prompt = " [y/n] "
|
|
36
|
+
elif default == "yes":
|
|
37
|
+
prompt = " [Y/n] "
|
|
38
|
+
elif default == "no":
|
|
39
|
+
prompt = " [y/N] "
|
|
40
|
+
else:
|
|
41
|
+
raise ValueError("invalid default answer: '%s'" % default)
|
|
42
|
+
|
|
43
|
+
while True:
|
|
44
|
+
sys.stdout.write(question + prompt)
|
|
45
|
+
choice = input().lower()
|
|
46
|
+
if default is not None and choice == '':
|
|
47
|
+
return valid[default]
|
|
48
|
+
elif choice in valid:
|
|
49
|
+
return valid[choice]
|
|
50
|
+
else:
|
|
51
|
+
sys.stdout.write("Please respond with 'yes' or 'no' "
|
|
52
|
+
"(or 'y' or 'n').\n")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_new_user_information():
|
|
56
|
+
email = input("What's your email? ")
|
|
57
|
+
username = input("What username would you like? ")
|
|
58
|
+
password = getpass.getpass("What password? ")
|
|
59
|
+
print("\nEmail: " + email + " Username: " + username)
|
|
60
|
+
all_good = query_yes_no("Are these correct?")
|
|
61
|
+
|
|
62
|
+
if all_good:
|
|
63
|
+
return RegisterUser(email, username, password)
|
|
64
|
+
else:
|
|
65
|
+
return get_new_user_information()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_user_information_and_login(username=None, password=None, attempts=0):
|
|
69
|
+
if attempts == 4:
|
|
70
|
+
print("Too many bad attempts.")
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
# Only collect user information if we don't already have it
|
|
74
|
+
# i.e. if we didn't just register a new user.
|
|
75
|
+
if username == None and password == None:
|
|
76
|
+
print("Please enter your bashhub credentials")
|
|
77
|
+
username = input("Username: ")
|
|
78
|
+
password = getpass.getpass("Password: ")
|
|
79
|
+
|
|
80
|
+
# login once we have all of our information
|
|
81
|
+
access_token = rest_client.login_user(LoginForm(username, password))
|
|
82
|
+
|
|
83
|
+
# Package our result to include our credentials to later login our system.
|
|
84
|
+
if access_token:
|
|
85
|
+
result = (username, password, access_token)
|
|
86
|
+
else:
|
|
87
|
+
result = get_user_information_and_login(attempts=attempts + 1) or (
|
|
88
|
+
None, None, None)
|
|
89
|
+
|
|
90
|
+
return result
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_mac_address():
|
|
94
|
+
"""Get the mac address for our system as a fingerprint. If we can't
|
|
95
|
+
get the mac, use the hash of our hostname as a subtitute"""
|
|
96
|
+
|
|
97
|
+
mac = uuid.getnode()
|
|
98
|
+
# check if getnode fails
|
|
99
|
+
if (mac >> 40) & 1:
|
|
100
|
+
hostname = socket.gethostname()
|
|
101
|
+
print("warning: cannot find MAC. Using hostname (%s) to identify system" % hostname)
|
|
102
|
+
mac = hostname
|
|
103
|
+
else:
|
|
104
|
+
mac = str(mac)
|
|
105
|
+
return mac
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# Update our hostname incase it changed.
|
|
109
|
+
def update_system_info():
|
|
110
|
+
mac = get_mac_address()
|
|
111
|
+
hostname = socket.gethostname()
|
|
112
|
+
patch = SystemPatch(hostname=hostname, client_version=__version__)
|
|
113
|
+
return rest_client.patch_system(patch, mac)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def handle_system_information(username, password, attempts=0):
|
|
117
|
+
|
|
118
|
+
mac = get_mac_address()
|
|
119
|
+
system = rest_client.get_system_information(mac)
|
|
120
|
+
system_name = None
|
|
121
|
+
# Register a new System if this one isn't recognized
|
|
122
|
+
if system is None:
|
|
123
|
+
hostname = socket.gethostname()
|
|
124
|
+
name_input = input("What do you want to call this system? " +
|
|
125
|
+
"For example Home, File Server, ect. [%s]: " %
|
|
126
|
+
hostname)
|
|
127
|
+
|
|
128
|
+
name = name_input or hostname
|
|
129
|
+
system_name = rest_client.register_system(RegisterSystem(
|
|
130
|
+
name, mac, hostname, __version__))
|
|
131
|
+
if system_name:
|
|
132
|
+
print("Registered a new system " + name)
|
|
133
|
+
else:
|
|
134
|
+
if attempts < 3:
|
|
135
|
+
print("Looks like registering your system failed. Lets retry.")
|
|
136
|
+
return handle_system_information(username, password, attempts + 1)
|
|
137
|
+
else:
|
|
138
|
+
return (None, None)
|
|
139
|
+
|
|
140
|
+
# Login with this new system
|
|
141
|
+
access_token = rest_client.login_user(LoginForm(username, password, mac))
|
|
142
|
+
|
|
143
|
+
if access_token is None:
|
|
144
|
+
print("Failed to login with system.")
|
|
145
|
+
return (None, None)
|
|
146
|
+
|
|
147
|
+
# If this system is already registered
|
|
148
|
+
if system is not None:
|
|
149
|
+
system_name = system.name
|
|
150
|
+
print("Welcome back! Looks like this box is already registered as " +
|
|
151
|
+
system.name + ".")
|
|
152
|
+
|
|
153
|
+
return (access_token, system_name)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def main():
|
|
157
|
+
try:
|
|
158
|
+
|
|
159
|
+
ascii_art = r"""
|
|
160
|
+
____ _ _ _
|
|
161
|
+
| _ \ | | | | | |
|
|
162
|
+
| |_) | __ _ ___| |__ | |__ _ _| |__ ___ ___ _ __ ___
|
|
163
|
+
| _ < / _` / __| '_ \| '_ \| | | | '_ \ / __/ _ \| '_ ` _ \
|
|
164
|
+
| |_) | (_| \__ \ | | | | | | |_| | |_) | (_| (_) | | | | | |
|
|
165
|
+
|____/ \__,_|___/_| |_|_| |_|\__,_|_.__(_)___\___/|_| |_| |_|
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
print(ascii_art)
|
|
170
|
+
print("Welcome to bashhub setup!")
|
|
171
|
+
is_new_user = query_yes_no("Are you a new user?")
|
|
172
|
+
|
|
173
|
+
# Initialize variaous Credentials for logging in.
|
|
174
|
+
username = None
|
|
175
|
+
password = None
|
|
176
|
+
access_token = None
|
|
177
|
+
|
|
178
|
+
# If this is a new user walk them through the registration flow
|
|
179
|
+
if is_new_user:
|
|
180
|
+
register_user = get_new_user_information()
|
|
181
|
+
register_result = rest_client.register_user(register_user)
|
|
182
|
+
if register_result:
|
|
183
|
+
print("Registered new user {0}\n".format(
|
|
184
|
+
register_user.username))
|
|
185
|
+
# Set our credentials to login later
|
|
186
|
+
username = register_user.username
|
|
187
|
+
password = register_user.password
|
|
188
|
+
else:
|
|
189
|
+
print("Sorry, registering a new user failed.")
|
|
190
|
+
print("You can rerun setup using 'bashhub setup' in a new "
|
|
191
|
+
"terminal window.\n")
|
|
192
|
+
sys.exit(0)
|
|
193
|
+
|
|
194
|
+
(username, password, access_token) = get_user_information_and_login(
|
|
195
|
+
username, password)
|
|
196
|
+
if access_token == None:
|
|
197
|
+
print("\nSorry looks like logging in failed.")
|
|
198
|
+
print("If you forgot your password please reset it. "
|
|
199
|
+
"https://bashhub.com/password-reset")
|
|
200
|
+
print("You can rerun setup using 'bashhub setup' in a new "
|
|
201
|
+
"terminal window.\n")
|
|
202
|
+
sys.exit(0)
|
|
203
|
+
|
|
204
|
+
# write out our user scoped access token
|
|
205
|
+
config_write_result = write_to_config_file("access_token",
|
|
206
|
+
access_token)
|
|
207
|
+
if not config_write_result:
|
|
208
|
+
print("Writing your config file failed.")
|
|
209
|
+
sys.exit(1)
|
|
210
|
+
|
|
211
|
+
(access_token, system_name) = handle_system_information(username,
|
|
212
|
+
password)
|
|
213
|
+
|
|
214
|
+
if access_token == None:
|
|
215
|
+
print("Sorry looks like getting your info failed.\
|
|
216
|
+
Exiting...")
|
|
217
|
+
sys.exit(0)
|
|
218
|
+
|
|
219
|
+
# write out our system scoped token and the system name
|
|
220
|
+
write_to_config_file("access_token", access_token)
|
|
221
|
+
write_to_config_file("system_name", system_name)
|
|
222
|
+
update_system_info()
|
|
223
|
+
|
|
224
|
+
sys.exit(0)
|
|
225
|
+
|
|
226
|
+
except Exception as err:
|
|
227
|
+
sys.stderr.write('Setup Error:\n%s\n' % str(err))
|
|
228
|
+
traceback.print_exc()
|
|
229
|
+
sys.exit(1)
|
|
230
|
+
except KeyboardInterrupt:
|
|
231
|
+
# To allow Ctrl+C (^C). Print a new line to drop the prompt.
|
|
232
|
+
print("")
|
|
233
|
+
sys.exit()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
if __name__ == "__main__":
|
|
237
|
+
main()
|
bashhub/bh.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import sys
|
|
5
|
+
import io
|
|
6
|
+
import os
|
|
7
|
+
import traceback
|
|
8
|
+
import datetime
|
|
9
|
+
from .bashhub_globals import *
|
|
10
|
+
from . import rest_client
|
|
11
|
+
from .i_search import InteractiveSearch
|
|
12
|
+
from .version import version_str
|
|
13
|
+
|
|
14
|
+
@click.command()
|
|
15
|
+
@click.argument('query', type=str, default='')
|
|
16
|
+
@click.option('-n', '--number', default=None, help='Limit the number of previous commands. Default is 100.', type=int)
|
|
17
|
+
@click.option("-ses",
|
|
18
|
+
"--session",
|
|
19
|
+
help="Filter by specific session id. Default is None.",
|
|
20
|
+
default=None,
|
|
21
|
+
type=str)
|
|
22
|
+
@click.option("-d",
|
|
23
|
+
"--directory",
|
|
24
|
+
help="Search for commands within this directory.",
|
|
25
|
+
default=False,
|
|
26
|
+
is_flag=True)
|
|
27
|
+
@click.option("-sys",
|
|
28
|
+
"--system",
|
|
29
|
+
help="Search for commands created on this system.",
|
|
30
|
+
default=False,
|
|
31
|
+
is_flag=True)
|
|
32
|
+
@click.option("-i",
|
|
33
|
+
"--interactive",
|
|
34
|
+
help="Use interactive search. Allows you to select commands to run.",
|
|
35
|
+
default=False,
|
|
36
|
+
is_flag=True)
|
|
37
|
+
@click.option("-dups",
|
|
38
|
+
"--duplicates",
|
|
39
|
+
help="Include duplicates",
|
|
40
|
+
default=False,
|
|
41
|
+
is_flag=True)
|
|
42
|
+
@click.option("-t",
|
|
43
|
+
"--timestamps",
|
|
44
|
+
help="Include timestamps",
|
|
45
|
+
default=False,
|
|
46
|
+
is_flag=True)
|
|
47
|
+
@click.option("-V",
|
|
48
|
+
"--version",
|
|
49
|
+
help="Print version information",
|
|
50
|
+
default=False,
|
|
51
|
+
is_flag=True)
|
|
52
|
+
def bh(query, number, session, directory, system, interactive, duplicates, timestamps, version):
|
|
53
|
+
"""Bashhhub Search
|
|
54
|
+
|
|
55
|
+
QUERY - Like string to search for
|
|
56
|
+
"""
|
|
57
|
+
limit = number
|
|
58
|
+
system_name = BH_SYSTEM_NAME if system else None
|
|
59
|
+
path = os.getcwd() if directory else None
|
|
60
|
+
session_id = session
|
|
61
|
+
|
|
62
|
+
# By default show unique on the client.
|
|
63
|
+
unique = not duplicates
|
|
64
|
+
|
|
65
|
+
use_timestamps = timestamps
|
|
66
|
+
|
|
67
|
+
# If we're interactive, make sure we have a query
|
|
68
|
+
if interactive and query == '':
|
|
69
|
+
query = input("(bashhub-i-search): ")
|
|
70
|
+
|
|
71
|
+
if version and query == '':
|
|
72
|
+
print(version_str)
|
|
73
|
+
sys.exit()
|
|
74
|
+
|
|
75
|
+
# Call our rest api to search for commands
|
|
76
|
+
commands = rest_client.search(limit=limit,
|
|
77
|
+
path=path,
|
|
78
|
+
query=query,
|
|
79
|
+
system_name=system_name,
|
|
80
|
+
unique=unique,
|
|
81
|
+
session_id=session_id)
|
|
82
|
+
|
|
83
|
+
if interactive:
|
|
84
|
+
run_interactive(commands)
|
|
85
|
+
else:
|
|
86
|
+
print_commands(commands, use_timestamps)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def print_commands(commands, use_timestamps):
|
|
90
|
+
for command in reversed(commands):
|
|
91
|
+
if use_timestamps:
|
|
92
|
+
timestamp = unix_milliseconds_timestamp_to_datetime(command.created)
|
|
93
|
+
print('%s\t%s' % (timestamp, command.command))
|
|
94
|
+
else:
|
|
95
|
+
print(command.command)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def run_interactive(commands):
|
|
99
|
+
i_search = InteractiveSearch(commands, rest_client)
|
|
100
|
+
i_search.run()
|
|
101
|
+
# numpy bullshit since it doesn't return anything.
|
|
102
|
+
# Consider submitting a patchset for it.
|
|
103
|
+
command = i_search.return_value
|
|
104
|
+
if command is not None:
|
|
105
|
+
f = io.open(BH_HOME + '/response.bh', 'w+', encoding='utf-8')
|
|
106
|
+
print(command.command, file=f)
|
|
107
|
+
|
|
108
|
+
def unix_milliseconds_timestamp_to_datetime(timestamp):
|
|
109
|
+
return datetime.datetime.fromtimestamp(int(timestamp) / 1000) \
|
|
110
|
+
.strftime('%Y-%m-%d %H:%M:%S')
|
|
111
|
+
|
|
112
|
+
def main():
|
|
113
|
+
try:
|
|
114
|
+
bh()
|
|
115
|
+
except Exception as e:
|
|
116
|
+
if BH_DEBUG:
|
|
117
|
+
traceback.print_exc()
|
|
118
|
+
click.echo("Oops, look like an exception occured: " + str(e))
|
|
119
|
+
sys.exit(1)
|
|
120
|
+
except KeyboardInterrupt:
|
|
121
|
+
# To allow Ctrl+C (^C). Print a new line to drop the prompt.
|
|
122
|
+
click.echo()
|
|
123
|
+
sys.exit()
|
|
124
|
+
|
|
125
|
+
main()
|