SUDO using SSH Keys

*Warning: I offer no guarantees this will work for you, and mis-configuration could end up with no access to your system*

It’s really annoying if you’ve connected SSH using keys that you’re prompted for a password when trying to use sudo. Particularly when using scripts. You can certainly use the NOPASS option in sudoers, but for various reasons may not want to.

I’ve gone for the option of (if SSH Key then allow sudo, if not prompt for password) something you couldn’t do with the NOPASS option.

First install libpam-ssh-agent-auth

apt-get install libpam-ssh-agent-auth

Then edit /etc/pam.d/sudo adding the following above the first sessions line:

auth [success=3 default=ignore] pam_ssh_agent_auth.so file=/etc/ssh/sudo_authorized_keys

Next edit /etc/sudoers and add above the existing Defaults:

Defaults env_keep += "SSH_AUTH_SOCK"

Finally edit /etc/ssh/sudo_authorized_keys and add your key.
It’s recommended you set the permission on this file to root only.

Now without closing your current connection, test the setup with a new ssh session. You should be able to connect and sudo without a password.
If you have password authentication enabled for connection normally, test this is still working, and when you use sudo you should be prompt again for the password.

This is working for me on Ubuntu, but as the warning above incorrect configuration may result in locking yourself out.

Raspberry PI 4 Boot from USB HDD not working GPT

This is more of a note for me than a guide or help for anyone else.

At present the PI4 does NOT support boot from USB, but you can work around this like the old days by using an SD card for the /boot and setting this to load the root from USB Stick/HDD.

However, this only appears to work for me using MBR partition type and just hangs when using GPT. This may be because I’m also encrypting the disk and using headless network boot. But that side does work and the disk/paritions are decrypt and list in /dev/disk/by-label but the OS just will NOT boot for me. Copying everything to the exact same partition layout and labels under MBR and it just works.

It seems a weird problem, as the SD card that’s actually booting and has the kernel is MBR and I don’t see why it would then care, the kernel has to be aware of GPT and as I said lists everything correctly. I can even decrypt and mount during the dropbear network boot bit, but the OS just wont boot. Workaround at present is to place the OS on it’s own drive/stick and use GPT on bigger disks purely for data. I’ve only found this while trying to use a 5Tb disk for both OS and Data. the 2Tb disk I can use MBR on without loosing space so the workaround isn’t really needed, just use MBR.

Raspberry PI 4 Blink Power LED (Locate in Cluster)

I bought a small cluster rack for my Raspberry PI 4’s. I have 4 of them racked and the idea was to keep it simple, assign static IP addresses .80,.81,.82,.83 with {NAME}-00, {NAME}-01 etc, starting at the bottom. Makes complete sense! however before I bought the rack they were all laid out flat and I thought in order left to right. When it came time to rack them I carefully screwed them all in place and powered up. All good. That is until I needed to work on No.3, shut it down and found it 2nd up in the rack 🙁 No.1 was next and No.2 on top. I don’t think I could have made the order worse if I was trying to lol.

Anyway, I finally got a bit of time to sort out the order. I’d already powered down No.2 and I know 100% No.0 is on the bottom. but that still left 50/50 that I’d be moving the correct PI (having to take the entire rack apart). So I thought I must be able to blink the ACT LED. Well a quick test and yes you can but disk access overrides it, so it’s not exactly great. but then I found contrary to what one of the guides say that the PWR LED can be controlled, it’s not just hard wired to 3v (this may be true on earlier PI’s, no idea and I don’t need to test it atm).

So a nice quick script:

nano locate_pi.sh
#!/bin/bash

# Setup the keyboard interrupt.
trap '{ echo "Stop Blinking. Setting LED to ON." ; echo 1 > /sys/class/leds/led1/brightness ; exit 0 ; }' INT

# Blink the Power LED
echo "Blinking Power LED..."
i=0
while true ; do
echo $i > /sys/class/leds/led1/brightness
sleep 1
i=$(((i==0?1:0)))
done

Make it executable:

chmod +x locate_pi.sh

Then you can run it:

./locate_pi.sh

And hey presto a nice flashing LED on the PI in a rack. Now you could be really fancy and assign a few different patterns of flashes by doing a bit of coding in the ‘while’ or simply adjusting the sleep time if your lazy. That could allow you to find more than 1 pi if you set them to blink differently but for my use a simple blink is plenty (for now).

As always, hope this helps someone. you could even move the locate_pi.sh to /bin or /usr/bin to allow you to just run it from wherever you are.

NB: I’m assuming writing to /sys/class/leds/led1/brightness can only be done by root (unless you change the permissions), as such this script will need to be run as root to work but I haven’t test as another user to know if this is true.

Remove/Hide WooCommerce Mine Status Filter

So this has been annoying me for ages.

I don’t really get what’s it for, more-so because I’m the only shop admin! Either all the orders are “Mine” or none of them.
I remember searching for why previously and came across a bug during a WooCommerce Database update that caused orders to be re-assigned to the owner id 1 if they were set at 0 or something similar. But it didn’t really explain the purpose of this filter and I didn’t get any further in my understanding of why anyone might find it useful.
There was a suggestion that it would come into play for order that were created using the ‘Add Order’ button. Now I can see that may be useful, I do occasionally create orders manually for customers who are having problems and this could be a way of finding them, but there’s no way I’ve manually create the hundreds or thousands that’s there (depending on which site I’m looking at, we have a few).

Not getting anywhere on finding to disable or hide it and just finding lots of info on custom statuses, I gave up. I did consider using CSS to just hide it but I really hate working on CSS when I have to. This wasn’t annoying enough that I had to.

But today I noticed our ‘Pending Payment’ count was rather high. We’ve had a busy month and I haven’t had time to pay attention to the small details. but almost 300 orders ‘Pending Payment’ raised my interest. That was quite cimply that the cronjob to clear them wasn’t there, and I vaguely remembered this happening a few years back. Clearing the inventory timeout, save and setting it back to 60 mins (and save) recreate the cron job. That fired straight away and cancelled half of the orders there. I gave it a few mins and force run the cronjob again, that cleared the queue right down to about 8 orders. 2 of them are valid carts going through now and 6 are manual orders that may/may not have been paid (I need to check each of them) but were holding orders (not really shipping anything) so not an issue.

Once I finished with ‘Pending Payment’ I spotted the ‘Mine’ filter again, which brought back ‘why is it there, can I get rid of it?, it’s totally pointless for me. It just takes up room.

Well people I can say, you can hide it 😀 and it’s pretty easy to do.

You can add the following to your functions.php

function hide_mine_filter_shop_orders( $views ) {
    // Unset the option from the views
    unset( $views['mine'] );
    return $views;
};
add_filter( 'views_edit-shop_order', 'hide_mine_filter_shop_orders' );

And it’s now gone:

** The pics are from 2 different sites. I’ll be applying it to all shortly 🙂

I know it’s not much, but I’ve never used it and with lots of different order status’ it much better to have one less.

I should add just in case I ever read this again, I actually put that in one of our own plugins that restores the Items Purchased column that was removed from WooCommerce Core but crucial to speedily deal with orders (that still should have been a tick option in screen options, but the devs wouldn’t take that on board).

Domoticz Bluetooth Presence Detection

Update script being used as presence detection. Previously would take arguments for -s and -b (switch and bluetooth) and only check 1 device. Required multiple cron entries, 1 for each device. This could lead to polling issues if more devices are added. This new script “Should” only poll once for all devices. There’s a pause when it’s searching for the first device but consecutive devices fly through so I think it’s working.

Python Script saved in /home/domoticz/domoticz/bluetooth/bluescan.py

#!/usr/bin/python

import bluetooth
import time
import argparse
import urllib
import urllib2
import json

parser = argparse.ArgumentParser(description='SwitchID BluetoothID')
parser.add_argument('-l', '--link', action='append', help='BluetoothMac-SwitchID', required=True)
parser.add_argument('-d', '--debug', help='Debug Output', required=False, action='store_true')
parser.add_argument('-u', '--updatefound', help='Always update Found Devices', required=False, action='store_true')
args = parser.parse_args()

def update_switch(args, switchid, status):
URL="http://127.0.0.1/json.htm?username=YWRtaW4=&password=ZG9tb3RpY3o=&type=command&param=switchlight&idx={0}&switchcmd={1}".format( switchid, status )
if args.debug:
print URL
request = urllib2.Request(URL)
response = urllib2.urlopen(request)
return response.read()

if args.debug:
print "Checking " + time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime())

for value in args.link:
s = value.split("-")
blueid, switchid = s[0], s[1]
if args.debug:
print ("Switch ID: %s" %switchid )
print ("Bluetooth ID: %s" %blueid )

#Get the current status
URL="http://127.0.0.1/json.htm?username=YWRtaW4=&password=ZG9tb3RpY3o=&type=devices&rid={0}".format( switchid )
if args.debug:
print URL
response = urllib2.urlopen(URL)
json_data = json.load(response)
current_status = json_data['result'][0]['Status']
if args.debug:
print ("Current Status: %s" %current_status )

result = bluetooth.lookup_name(blueid, timeout=10)

if (result != None):
if args.debug:
print "Found"
# status = 1
status = "On"
else:
if args.debug:
print "NOT Found"
# status = 0
status = "Off"

if current_status == status:
if args.debug:
print "Status UnChanged"
if status=="On" and args.updatefound:
update = update_switch( args, switchid, status )
if args.debug:
print update
else:
update = update_switch( args, switchid, status )
if args.debug:
print update

Cronjob as user domoticz

* * *   *       *       /home/domoticz/domoticz/bluetooth/bluescan.py -u -l C0:EE:FB:00:00:00-7 -l A0:82:1F:00:00:00-23

Had to us – as separator. : in mac address would be confusing, tried ; but conflicts with bash, was going to use a space but would need to account for that in the argument parser and – was just easier.

Google Translate Text-to-Speech Linux

Scroll down for the script, or read who/why we use it first 🙂

I’ve been using a brilliant script by Dan Fountain for a few years as part of a WooCommerce barcode scanner python program I made. It allows us to update/process orders without the need of working in the admin interface 90% of the time.
For this we use a Raspberry PI, and a handheld portable barcode scanner. One of the big things that was needed was feedback from the PI as to what it’s done or what it’s doing. I’ve attached an LCD screen and most recently added a whole web interface output (mainly for diagnostics), but when your scanning a bunch of orders especially in bulk you dont want to be looking at a very small LCD screen about 4m away. So I added speakers and TTS.

There’s a few different things the barcode program can do (get order status, add tracking code to the order) but the most important is update the status of the order.
We start processing orders first thing in the morning by scanning a ‘bulk’ QR code, then scanning each order that’s on the printer. Once they’ve all been scanned we scan another QR Code ‘Order Printed’. Quite simply this updates each order status from ‘processing’ to ‘printed’, and this is important in case Google Cloud Print fails to print an order (it does from time to time), anything left in ‘processing’ needs checking.

Anyway that’s not the important bit for this post! The important bit is the python program giving audio feedback. While we could have gone for a TTS engine local to the pi, Google Translate option gives a far better sounding voice. The above scenario would do the following:
We scan Bulk mode
Pi says ‘Bulk Capture Active’
We scan first order
PI says ‘One’
We scan second order
PI says ‘two’
and on
and on
Once all the orders are scanned, we then scan ‘Printed’
PI says ‘Bulk Capture Finished. Processing x’ where x is the number of orders.
PI says ‘One’
PI says ‘Two’
etc. etc.
Then Pi Finally says ‘Finished Bulk Processing’.

Now there’s certainly the ability to pass all the orders in one go via the WooCommerce API, but we handle them as individual requests within python so that we can do some order status checking before changing it’s status. i.e if an order has already been moved from ‘processing’ to say ‘cancelled’ we dont want to move it again to ‘printed’, at that point the PI would say ‘Error Processing Order xxxxxx’ where xxxxxx is the order number.

As you can see from the above flows, the actual text being read ends up being the same text over and over and over. The number ‘One’ can be read about 10 times as we bulk move things around queues. While it’s certainly possible to just fire the same thing at Google Translate over ad over, it’s far nicer to play friendly and cache what we can use again and again.

The code below is based on the awesome work of Dan Fountain, with the following updates:
Added Caching
Added MPG123 options (to speed up the play back a little)
Added a client to the wget request (without it google started blocking heavy requests when the cache is clear).

#!/bin/bash
#################################
# Speech Script by Dan Fountain #
#      [email protected]     #
#                               #
# Added caching by JDL          #
#################################

CACHE=/tmp/ttscache

mkdir -p $CACHE

INPUT=$*
STRINGNUM=0
MPG123OPTS="-h 3 -d 4 -m --stereo -q"

ary=($INPUT)
for key in "${!ary[@]}"
  do
    SHORTTMP[$STRINGNUM]="${SHORTTMP[$STRINGNUM]} ${ary[$key]}"
    LENGTH=$(echo ${#SHORTTMP[$STRINGNUM]})
    #echo "word:$key, ${ary[$key]}"
    #echo "adding to: $STRINGNUM"
    if [[ "$LENGTH" -lt "100" ]]; then
      #echo starting new line
      SHORT[$STRINGNUM]=${SHORTTMP[$STRINGNUM]}
    else
      STRINGNUM=$(($STRINGNUM+1))
      SHORTTMP[$STRINGNUM]="${ary[$key]}"
      SHORT[$STRINGNUM]="${ary[$key]}"
    fi
done

for key in "${!SHORT[@]}"
  do
    #echo "line: $key is: ${SHORT[$key]}"

    echo "Playing line: $(($key+1)) of $(($STRINGNUM+1))"
    NEXTURL=$(echo ${SHORT[$key]} | xxd -plain | tr -d '\n' | sed 's/\(..\)/%\1/g')
    URL="http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=$NEXTURL&tl=En-gb"
    URLMD5=`/bin/echo $URL | /usr/bin/md5sum | /usr/bin/cut -f1 -d" "`
    if [ -s "$CACHE/$URLMD5" ]
    then
       mpg123 $MPG123OPTS "$CACHE/$URLMD5"
    else
       echo "Getting : $URL"
       wget -U "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" "$URL" -O $CACHE/$URLMD5
       mpg123 $MPG123OPTS "$CACHE/$URLMD5"
    fi
done

##!/bin/bash
#say() { local IFS=+;/usr/bin/mplayer -ao alsa -really-quiet -noconsolecontrols "http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=$*&tl=En-us"; }
#say $*

WooCommerce Nag Notice

We all (mostly) understand updates are important and I’m sure there were only good intentions by setting it but the
‘Connect your store to WooCommerce.com to receive extensions updates and support.’
Nag notice is ridiculous. A non-dismissable notice should never be allowed. I get you dont want people to just quickly click the dismiss button, so why not put an option at the bottom of the connect page ‘Dismiss this alert. I understand what this means’ even if it only dismissed for say 3 months and then you had to do it again. It would still be annoying but at least easier to deal with.

But no, in someones infinite wisdom they’ve decided you absolutely must connect your store and have no other option. Well here’s the code to add to stop that nag notice

add_filter( 'woocommerce_helper_suppress_admin_notices', '__return_true' );

** It is your own responsibility to keep your site upto date.
** Disabling this notice, may disable other woocommerce notices.

There are of course legitimate reasons why would wouldn’t want to connect your store, managing your updates your own way should always be allowed. So dev’s stop trying to dictate how you want/think things should run, choice is the key.

WooCommerce 3.3.0+

Yesterday upgrade a store to WooCommerce 3.3.1 from whatever the hell it was on before.

Today I’ve spent the day putting things right 😠 All the issues are around the new Orders UI and it seems like petty small stuff but it’s safe to say I’m hating the new UI because I’ve wasted the day dealing with over 50 complaints.
For those unfamiliar here’s the proposed changes (the end result is a little different) https://woocommerce.wordpress.com/2017/11/16/wc-3-3-order-screen-changes-including-a-new-preview-function-ready-for-feedback/#comment-4137

I’ve so far fixed some of the issues, such as rearranging the columns (why the actual fu*k status was moved I’ll never know or understand). The below code is probably not the best way to do it, but it works

// Function to Change the order of the Columns
function woocommerce_myinitials_restore_columns( $columns ) {
    $new_order = array(
       'cb' => '',
       'order_status' => '',
       'csv_export_status' => '', // dont think this ones standard but it's part of a plugin we use.
       'order_number' => '',
       'order_items' => '',
       'billing_address' => '',
       'shipping_address' => '',
       'order_date' => '',
       'order_total' => '',
       'wc_actions' => '',
    );
    foreach($columns as $key => $value) {
       $new_order[$key] = $value;
    }

    return $new_order;
}
add_filter( 'manage_edit-shop_order_columns', 'woocommerce_myinitials_restore_columns',99 );

So that’s one issue solved. The next was being able to click anywhere in the row opens the order (yeah I’m sure that’s nice, but if you rely on tapping a touchscreen i.e. click and drag to scroll then this causes problems). The following code adds the no-link class to the tr and stops this shitty behaviour

function woocommerce_myinitials_restore_columns_add_nolink_class( $classes ) {
    if ( is_admin() ) {
        $current_screen = get_current_screen();
        if ( $current_screen->base == 'edit' && $current_screen->post_type == 'shop_order' ) {
            $classes[] = 'no-link';
        }
    }
    return $classes;
}
add_filter( 'post_class', 'woocommerce_myinitials_restore_columns_add_nolink_class' );

Thanks on this one goes to ‘rodrigoprimo’ for the initial fix and others who picked it up and added a bit to it https://github.com/woocommerce/woocommerce/pull/18708.

I’ve added the following as a stylesheet

.post-type-shop_order .wp-list-table td, .post-type-shop_order .wp-list-table th {
   vertical-align: unset;
}

.post-type-shop_order .wp-list-table td.order_status {
   vertical-align: middle;
   text-align: center;
}

This places the orders back at the top of the row, and stops the previous restoration of items sold link jumping around. but I’d rather the new status text stays in the middle inline with the checkbox, hopefully we’ll get this back to an icon soon.

All of the above I’ve added to our custom plugin, you could either do this or add them to your functions.php

Outstanding issues:
1. Getting back the Email address. There is some hope this may come back officially, but I’ll be fixing it for us tomorrow.
2. The Status being text not icons. I understand this makes more sense to new users but if you have some long statuses like we do, the text doesn’t fit and we’ve got 10 statuses all looking the same. Having coloured icons worked for us and if you weren’t sure hover the mouse. I’ll be looking to get them back to icons tomorrow.
3) Date column, just why! Why would anyone think not putting the actual date and time of the order here is a good idea. Stupid ‘X mins ago’ is no use at all.

The new preview window looks good but I really dont see it getting much use, we need the important data on the front. If it’s not that important just open the order. WooCommerce dev’s decided to screw with it but I dont think there’s an understanding that if your going as far as opening the preview window then I’m pretty sure you were used to just editing the order which is probably still going to be the case.

So summing up today, I’ve had a shit day of people moaning at me because some developers decided to improve something that really didn’t need touching. Doesn’t sound like every developer I’ve ever known 😂. I’m now getting something to eat before I go near everything I’d planned on working on today.

Setting NGINX + PHPLDAPADMIN location & php for subfolder

Spent far too long trying out different ways to get this to work. I need to setup a server listening to the local IP address to restrict things like phpldapadmin to internal requests. But hit problems with nginx appending the location to the root path, and php having no idea where to get the files from.

Here’s the config that ended up working

server {
listen 80;
root /var/www/default/;

index index.html index.htm index.nginx-debian.html;

server_name 192.168.0.3;

location = / {
        try_files $uri $uri/ =404;
}

location /phpldapadmin {
        alias /usr/share/phpldapadmin/htdocs;
        index index.php index.html index.htm;

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;

                # With php7.0-fpm:
                fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                fastcgi_intercept_errors on;
        }
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
        include snippets/fastcgi-php.conf;

        # With php7.0-cgi alone:
        # fastcgi_pass 127.0.0.1:9000;
        # With php7.0-fpm:
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_intercept_errors on;
}

access_log /var/log/nginx/localip-access.log;
error_log /var/log/nginx/localip-error.log;
}