> Well, the people in the first category will usually be smart enough to setup a sync without using an external "cloud service".
Apart from some, like myself.
How would you go about it, given the need for 2-way sync? I've ruled out rsync, could see Git working but not particularly performant to run every 20 seconds to keep the history in sync between machines.
I use git to sync my dotfiles (pulled in by SaltStack because I'm crazy enough to put my workstations under config management) I just have a script that does a git commit -am "automated push on $(date)" that triggers when I lock my screen. It's not perfect but it works well enough for my needs, though I don't sync my bash history.
You are giving all your bash history to a third party, that is incredibly scary and if you can't see the security implications then you need to rethink your product.
the problem is, theres a pretty good chance people will still send all sorts of passwords and access credentials. that's a big liability if you get exploited.
should you do this? no.. but people do, all the time.. take for example this MySQL bug report with many complaints that the command now issues a warning when you specify a password on the command line:
https://bugs.mysql.com/bug.php?id=66546
Seriously I don't think you really understand the implications here or you aren't taking them seriously, if you did you sure wouldn't be talking about this so nonchalantly. You should seriously shut this down before you get some young programmers/admins fired or worse.
Also from your FAQ what the hell is "strong level encryption", can you not name it? Can you go into the extreme technical details of what encryption you are using, how data is protected in memory and at rest?
The FAQ says 'storage level encryption' which presumably means volume encryption, but in any case is unlikely to protect against anyone gaining access to the box, only against someone making off with the physical storage.
Creator here! Wow, didn't think this would get posted on HN all of a sudden. Would love to hear your feedback or ideas, I'm very actively developing the project. ryan@bashhub.com
[In case it wasn't clear, above was mildly tongue-in-cheek; secrets should not be in your bash history, but of course things approaching (and including) PII may well be]
Not saying I make of habit of this, but sometimes you have to pass sensitive things as arguments (passwords, api tokens, customer data, etc), it happens.
I think client side encryption by Bashhub would alleviate this security concern.
That doesn't have to mean typing it at your command line. My approach is typically to set shell variables with read (if I need to type it) or xclip (if I need to paste).
Of course, client side encryption would be great in any case.
I expect I might take more care about maintaining a tidy history (see my other comment about splitting out separate histories by context), and reflexively clear bits of my history when I don't want them hanging around in the way of a ctrl-r - which would certainly include bits of passwords and anything pasted.
That said, this seems to use PROMPT_COMMAND to log off history, which would not give the opportunity for such tidying. Worrisome.
Splitting history is done fundamentally by setting HISTFILE - nothing too surprising about that.
But for my particular setup, I more broadly divide my shell use by context. I have a script called "session". `session $somename` looks for a screen (feel free to prefer tmux) session named $somename. If one exists, it attaches it. If not, it spawns it. Before doing so, it sets a shell variable SESSION to $somename. My bash_profile then customizes a lot of things based on the contents of that variable, including adding $SESSION to the prompt, and sourcing ~/.session/$SESSION/bash_profile. This lets me set context-specific aliases and such. Because SESSION is set above the terminal multiplexer, new windows spawned while in one context share the same context.
I've found most of this quite nice, but the history is the biggest win.
This is offtopic, but do you have issues maintaining the right path to the SSH agent socket when switching between screen sessions? (tmux has the same issue)
The ssh agent forwarding info is stored in environment variables, which are then inherited by any other process spawned from your initial connection, so everything that cares knows the agent pid and where to find the agent socket.
The problem is that, with screen and tmux, the content of those environment variables outlasts their accuracy.
The solution needs to take the form of updating those environment variables. It looks like there's a .ssh_agent file that can be sourced to update it, though I'm not finding - at a skim of the docs - what creates that and when. It does only seem to contain info for a single socket, so assuming it's populated on login there's still a possibility of that data being stale:
connection 1 login
connection 1 writes info to file
connection 2 login
connection 2 writes info to file
connection 2 logout
leaves the info wrong if you try to use it from connection 1.
Better would be to store all active agent sessions. We can implement that as follows:
in .bash_profile:
if [ "$SSH_AUTH_SOCK" -a "$SSH_AGENT_PID" ]; then
exec {SSH_AGENT_INFOS_FD}>>~/.ssh_agent_infos
if flock $SSH_AGENT_INFOS_FD; then
sed -i "1i$SSH_AGENT_PID $SSH_AUTH_SOCK" ~/.ssh_agent_infos
fi
exec {SSH_AGENT_INFOS_FD}>&-
fi
This creates the file if it doesn't exist, locks it, and prepends the current session's info. It goes in .bash_profile, not .bashrc, so that it is only executed for login shells.
in .bash_logout:
if [ "$SSH_AUTH_SOCK" -a "$SSH_AGENT_PID" ]; then
flock .ssh_agent_infos sed -i "/^$SSH_AGENT_PID /d" .ssh_agent_infos
fi
This locks the file and strips out lines with a matching PID. .bash_logout is sourced on exit from a login shell.
in .bashrc, set BASH_PROMPT so that it includes the following (personally, my BASH_PROMPT is set to source ~/.bash_prompt):
exec {SSH_AGENT_INFOS_FD}>>~/.ssh_agent_infos
if flock -w 1 -s $SSH_AGENT_INFOS_FD; then
read -u $SSH_AGENT_INFOS_FD SSH_AGENT_PID SSH_AUTH_SOCK
fi
exec {SSH_AGENT_INFOS_FD}>&-
This will run every time a new prompt is generated (so, right after running the previous command, if any). It locks the file, and then reads the first line out of it to populate SSH_AGENT_ID and SSH_AUTH_SOCK. So if a shell has old values in those variables, you should just need to hit enter to repopulate them.
Note that the above assumes that, if you're logging in from multiple devices, your agents are interchangeable. If you need to keep them separate, then adjust the above to either tag the lines in .ssh_agent_infos or use multiple files.
Alas, not helpful here. The logging is done in PROMPT_COMMAND, meaning by the time you can type another command things are already logged and editing your history won't help. Hopefully (though I see no evidence of this, I've also only skimmed the material) things are marshalled somewhere locally and can be inspected/edited before being sent to the server.
This is very interesting. Somewhat related, by far my biggest history-related usability/efficiency win has been to separate out different history files for different contexts.
If you rely on your shell history to the level that you need synchronization via a cloud-based service, it should be a signal that your automation needs work.
"A file with the `a' attribute set can only be open in append mode for writing. Only the superuser or a process possessing the CAP_LINUX_IMMUTABLE capability can set or clear this attribute."
If the histappend shell option is enabled (see the description of shopt
under SHELL BUILTIN COMMANDS below), the lines are appended to the history
file, otherwise the history file is overwritten.
histappend
If set, the history list is appended to the file named
by the value of the HISTFILE variable when the shell
exits, rather than overwriting the file.
I have routinely kept my history "best effort" for many many years now by exporting HISTSIZE=10000 and HISTFILESIZE=1000000, and then occasionally doing a cp -a ~/.bash_history{,-$(date +%s)}. I actually use this history archive, and wish it was higher fidelity. (In practice, I am thinking I should just run all my sessions through script... ;P.)
I have thereby had it on my todo list for a month or so, ever since I learned of the bash DEBUG trap, to instead store my history into an sqlite3 database and have it separated by host. Seeing this reminded me "oh yeah, I really should do that" (as no: there's no way in hell I'm going to just send all of the commands I type to some random guy with a website ;P).
This is "the simplest thing that could possibly work" and might very well break if you set some crazy history configuration variables I don't use. Note that it works for pipes specifically and only because it can overwrite the same entry to the database multiple times using "insert or replace" (prevention of which is what normally makes these scripts so complex).
histsql=~/.bash_sqlite3
sqlite3 "${histsql}" '
create table if not exists "session" (
"id" integer not null primary key autoincrement,
"address" text not null,
"process" integer not null,
"tty" text not null,
"user" text not null,
"start" timestamp not null default current_timestamp,
"end" timestamp null
);
create table if not exists "command" (
"session" integer not null,
"line" integer not null,
"time" timestamp not null default current_timestamp,
"pwd" text not null,
"text" text not null,
primary key ("session", "line")
);
'
histmac=$(ifconfig | sed -e 's/ *$//; /\(ether\|HWaddr\) / { s/.* //; q; }; d;')
histtty=$(tty)
histssn=$(sqlite3 "${histsql}" "
insert into \"session\" (
\"address\", \"process\", \"tty\", \"user\"
) values (
'${histmac//\'/''}', '${$//\'/''}',
'${histtty//\'/''}', '${USER//\'/''}'
);
select last_insert_rowid();
")
function histend {
sqlite3 "${histsql}" "
update \"session\" set
\"end\" = current_timestamp
where
\"id\" = '${histssn//\'/''}';
"
}
trap histend EXIT
function histadd {
local data="$(HISTTIMEFORMAT= history 1)"
if [[ -z $data ]]; then return; fi
data="${data#"${data%%[![:space:]]*}"}"
local line="${data%%' '*}"
data="${data#*' '}"
data="${data#"${data%%[![:space:]]*}"}"
sqlite3 "${histsql}" "
insert or replace into \"command\" (
\"session\", \"line\",
\"pwd\", \"text\"
) values (
'${histssn//\'/''}', '${line//\'/''}',
'${PWD//\'/''}', '${data//\'/''}'
);
"
}
trap histadd DEBUG
"(In practice, I am thinking I should just run all my sessions through script... ;P.)"
I've been doing this for on-call work, actually. It really helps to be able to review what was seen, what was done, how long things took, &c.
For me, the purpose of a typescript is almost entirely unrelated to the purpose of a history, though - history is things I reach for, more than things I review.
There are people who would not be wary of sending this kind of information remotely to be stored by someone else.
But I think the intersection of these types would be small.