Running a shell command with a single click on a shelf shortcut on Chrome OS

I wanted to find a way to execute a shell command on a Chromebook via a single click on a bookmarked icon in the shelf. After a bit of research, I discovered a way to do it. It involves setting up the Chromebook as a ssh host, which is perhaps overkill, and could potentially have security implications, but also means I can access the chromebook's shell via ssh from my Android phone/tablet (or any other computer), which could be useful some day.

Here's how I did it on a freshly powerwashed device (in Developer mode). Not all of the below steps are strictly necessary; as ever, YMMV.

Briefly, what I did was: 

Installed Secure Shell extension; setup sshd on the Chromebook; added public key from ConnectBot (Android app) to ~/.ssh/authorized_keys in order to test connection; created profile to connect to chronos@localhost/my local IP address in Secure Shell extension; generated keys on Chromebook (in  ~/.ssh); added generated public key to ~/.ssh/authorized_keys; imported newly-generated private/public key pair within Secure Shell app (one by one); created bookmark link to chronos@localhost profile in shelf, and, finally, added required command to 'arguments' field of profile in Secure Shell.

A more detailed description follows.


1. Installed Secure Shell extension


Installed Secure Shell extension from https://chrome.google.com/webstore/detail/secure-shell/pnhechapfaindjhompbnflcldabbghjo?hl=en


2. (a) Added ssh upstart job to /etc/init/


Entered the following in the shell:

sudo ln -s /usr/share/chromeos-ssh-config/init/openssh-server.conf /etc/init/openssh-server.conf

The above file, openssh-server.conf, will auto-start sshd at boot, and, additionally, will add a firewall rule which opens port 22, enabling ssh access to the device from external networks. This firewall rule is only required if connecting from another device - to use ssh purely within the Chromebook, it is not necessary to open port 22. Therefore, if not intending to connect to the Chromebook from another device via ssh, one may create a .conf in /etc/init omitting this part. For instance, for purely accessing localhost, the following works for me:

sudo su -
echo "start on starting system-services

script

exec /usr/sbin/sshd

end script" > /etc/init/openssh-server.conf 
chmod 644 /etc/init/openssh-server.conf

2. (b) Registered and initialised upstart job


sudo initctl reload-configuration
sudo initctl start openssh-server 

The above pair of shell commands registered and then initialised the open ssh server. After entering the commands, the server was running in the background.


3. (a) Optional: Tested the connection with ConnectBot on Android tablet (Nexus 9)


This step is not actually necessary (unless you specifically want to control your Chromebook in the shell with an Android device).

Rebooted Chrome OS, launched ConnectBot, generated Pubkey, long-pressed on newly-generated key, chose Copy public key. Mailed it to self. Opened Gmail on the Chromebook, copied key from email, opened shell tab (non-root) and added the key to Chrome OS as follows:

(*DOUBLETAP* indicates a double tap on the touchpad to paste the key)

touch ~/.ssh/authorized_keys
echo *DOUBLETAP* > ~/.ssh/authorized_keys
chmod 600  ~/.ssh/authorized_keys

Created a new host profile in ConnectBot; set the second field as chronos@192.168.0.17 (my local IP address); left all other fields as default.

Connected to the profile...

chronos@localhost / $

Success! Disconnected ConnectBot. Back in the host profile, edited the field "Post-login automation". to add a shell command:

powerd_dbus_suspend

Connected to the profile...

The Chromebook sleeps!

Long pressed the N9 homescreen to bring up the "Add Widget" dialog. Dragged ConnectBot to homescreen. Chose chronos@192.168.0.17 from the pop-up list of hosts. Tapped the new homescreen shortcut...

The Chromebook sleeps!

Unfortunately, the current implementation of Android on Chrome OS doesn't appear to support  creating homescreen 'widget shortcuts'. So it seemed that another approach was required in order to create the one-click shortcut.


3. (b) Connected to the Chromebook... from the Chromebook


Opened Secure Shell extension in Chrome with the keyboard shortcut Ctrl+Alt+T, typed ssh, in omnibar, hit Tab, hit Enter.


Clicked on "New Connection"

Typed chronos@localhost

Clicked on "Connect"

At this point, it only seemed to be possible to connect after setting a password for chronos (passwd chronos), and then the password had to be entered manually at every connection. No good for automation. 

Some further setup seemed to be required.

Generated a new key, added the generated key to ~/.ssh/authorized_keys, and copied the keys to ~/Downloads.

cd ~/.ssh/
echo | ssh-keygen -P ''
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
cp -a ~/.ssh/id_rsa* ~/Downloads

Opened Secure Shell

Chose 'Import'

Navigated to private key in the file explorer (/home/chronos/user/Downloads/id_rsa). Clicked on it.

Chose 'Import', again

Navigated to public key in the file explorer (/home/chronos/user/Downloads/id_rsa.pub). Clicked on it.

Tried connecting to the chronos@localhost profile in Secure Shell again and... Boom!

chronos@localhost / $


4. Bookmarked the extension


With the Secure Shell profile command prompt tab open (which looks identical to the regular shell command prompt tab, except that in the address bar, rather than ending with crosh.html, the address ends with a profile number):

Three dot menu at top right>More tools>Add to shelf (open as window)

This created a clickable shelf bookmark icon.

5. Added the shell command


So now it was possible to open a shell command prompt with a single click, the final part of the puzzle was to add the command of interest. This turned out to be a piece of cake, once the syntax was correct. All that needed to be added to the saved Secure Shell profile was 

-- thecommand

...to the SSH Arguments field.

So, after adding 

-- powerd_dbus_suspend

to the SSH Arguments field for my chronos@localhost profile, the final result is a bookmark in the shelf which, when clicked, sends the Chromebook to sleep. Since I added it to the 9th position on the shelf, it can also be triggered with the keyboard shortcut: Alt+9.

I am not sure if it will be possible to set it up so that the command runs without opening a window, but it does at least seem to remember the window size and position, so the window can be hidden away at the side, or rolled up' into a small bar. I think it might be possible to set it up so the command runs in the background but I haven't looked into this yet.


Other use cases: Crouton etc.


Over on xda, user DandyRandyMarsh posted that he was able to successfully use this procedure to set up a shelf shortcut to open single apps within a crouton chroot in a window, simply by following the above and adding the relevant crouton command to the SSH Arguments field. He shared his example, a shortcut to enter steam;

-- sudo enter-chroot xiwi steam

One thing to bear in mind with this is that if your setup requires a password to sudo, you may need to change the command slightly. I haven't tested it out too much, but in my case, with a password prompt for sudo and a chroot on an external drive, I can open Firefox within my Ubuntu chroot in a xiwi window with a shelf shortcut after adding 

-t -- echo mypassword | sudo -S sh /media/removable/3/bin/enter-chroot xiwi firefox

to the Arguments field.

Similarly, I set up a shelf shortcut to open my chrooted Ubuntu desktop in a window with the argument

-t -- echo mypassword | sudo -S sh /media/removable/3/bin/startxfce4

Another way to do it is to save the string to a file in /usr/bin, then just put -- thefile as the argument. This is what I did with a few commands that I find it tedious to regularly open up a prompt and enter in, such as the ectool command(s) to switch off the bright LEDs on the side of the device:

sudo ectool led power off
sudo ectool led battery off


Customizing the icons


Of course, no-one wants a bunch of generic black squares darkening their desktop, so, in order to customize the shelf icon for these shortcuts, a few extra steps are necessary. 

Although the trick of injecting a favicon via js only seems to work for websites, and customizing the icon for Secure Shell itself might be pretty pointless as it'd be the same for all shortcuts (and get lost after the extension updates), we can set custom icons for our shell shortcuts as follows:

When you add shortcuts to the shelf on Chrome OS like this, a minimal app is created for each one, with its own manifest.json, and icon.pngs. Initially, the shell shortcuts were getting created with blank pngs as the icons by default (appearing as a black box with P in the center). 

So, all we need to do, is get some icons, find the right directory for our shelf shortcut app, then copy our new icons into it...

For instance, here's how I made a nice shiny icon for my single app shelf shortcut to Firefox.

(a) Prepared icons


Created a temporary directory in ~/Downloads to store my icons. 

Prepared a set of six icons in ~/Downloads/firefox. (I downloaded mine from findicons.com). 
To avoid any manifest editing, saved them as *size*.png



e.g. 32.png; 48.png; 64.png; 96.png; 128.png; 256.png

(b) Located correct directory to copy icons into; copied icons into folder:

Easy way:

As long as a somewhat unique name was chosen for the shelf shortcut, the easiest way to locate its directory is probably

cd ~/Extensions
grep -r thenameoftheshelfshortcut

Navigate to the Icons subdir, check its contents and copy over the new icons i.e. in my case:

cd thenameoftheshelfshortcut
cd */icons
ls
sudo cp ~/Downloads/firefox/* .

Other way:

If a generic name was chosen, and grepping it brings up too many results to go through,
another way to locate the correct directory is as follows:


(It is probably easiest to do this directly after clicking "add to shelf")

To change directory into the most recently modified extension icon subfolder automatically, the following works for me. 

cd ~/Extensions/&&cd $(ls -v1td */ | sed '/\Temp/d' | head -1)/&& cd $(ls -v1td */ | head -1)/icons&&ls -al
If the above one-liner worked correctly, a list of blank icons (*.png) should be visible. The file creation time/dates should be checked, and if they match the time the shortcut was added to the shelf, the directory is the right one, and new icons can simply be copied over these, e.g.

sudo cp ~/Downloads/firefox/* .


If the one-liner didn't work;  the icons directory can be located manually i.e.


ls -ltr ~/Extensions 

The most recently added folder is at the bottom. Then, 

cd themostrecentlyaddedfolder

(or, the folder modified at the date/time that the shortcut was "added to shelf"). Then,

cd */icons
ls
sudo cp ~/Downloads/firefox/* .

I repeated the above with a set of Ubuntu icons for my startxfce4 shortcut, and a few other Linux programs I use via crouton, for good measure.

Then just did sudo restart ui, and enjoyed the shiny new shelf icons!

I hope that these changes will get picked up by CrOS's extension sync, thus getting backed-up and restored automatically. At this point I am not sure if that will be the case, though.

Update regarding the latter: After an OS update, the only part that needed redoing was the SSH upstart job. After a powerwash, however, in addition to having to generate keys and add them to Secure Shell again, while the extension shortcuts (and Secure Shell profiles) themselves synced and restored OK , the icons did not. Next time, I'll see if adding a favicon URL instead of icon files works at all, and, if not, to restore them, I suppose I might have to add this into the customization scripts I run post-powerwash.

Sources:


(1) https://www.dereckson.be/blog/2015/01/15/chromebook-run-a-ssh-server-on-chrome-os/

(2) https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/master/chromeos-base/openssh-server-init/openssh-server-init-0.0.1.ebuild


(3) https://chromium.googlesource.com/apps/libapps/+/master/nassh/doc/FAQ.md


(4) https://groups.google.com/a/chromium.org/forum/#!msg/chromium-hterm/UpQRttX_LJk/Wj241kcSCAAJ

1 comment:

  1. Nice work. Quite a bit of effort but good workaround there.

    ReplyDelete