Category Archives: Tech

tech

Google Chrome extension to ensure the ‘Following’ tab in x.com (Twitter) remains selected

Twitter likes to play dirty tricks and deselect the ‘Following’ tab if you click on it. It seems to always rever to ‘For you’.

I’ve written a Google Chrome extension that ensures that the ‘Following tab’ is re-selected if it is not currently selected.

If you are using other tabs, this extension will be annoying to you since it will force ‘Following’ to be re-selected. Don’t use it.

You can download the extension here:

Instructions for use:

1. Download file
2. Unzip file to folder
3. Go to Exensions > Manage Extensions (or enter chrome://extensions/ in your address bar)
4. Make sure 'Developer Mode' is activated in the top-right corner
5. Click 'Load Unpacked' in the to-left corner and select the unpacked folder

The extension will now be automatically used whenever you visit x.com.

If you’re worried about the contents of the extension, open up content.js file. It’s the text file which contains the Javascript code. Very simple code with comments.

Using ChatGPT more effectively and getting better answers

I’ve been watching a few videos on how best to use ChatGPT. Various videos on YouTube can provide some great hints, tips, and tricks to get the most out of it.

I can recommend Leila Gharani’s YouTube channel.

I learned the following excellent piece of advice from one of her videos. You can add a specific set of instructions from the ‘Customize ChatGPT’ menu item by adding text to the ‘How would you like ChatGPT to respond?’ area.

I’m referring to the area below (in dark mode):

Add the following text:

Always add the confidence level of your answer. When your answer includes facts, always provide a valid URL with the source for your answer. Don't create a link for the URL, just write out the whole URL, including the http or https tag. If you speculate or predict something, inform me. If you think I may have misspelled code or a linux console command, please confirm my intention rather than assuming the correct syntax.

The last sentence I added from my own experience. This will tell ChatGPT to do several things:

  • Cite a confidence level for its answer – so you can decide whether to do more research or take the answer at its face value
  • Provide a URL so that you can look at the source of the link. ChatGPT always removed the links for me (probably for safety), so I asked it to spell out the URLs verbatim.
  • Indicate whether something given is speculation or a prediction or ‘fact’ – further allowing you to scrutinize answers.
  • Ensure that ChatGPT doesn’t make assumptions about what your intentions are when asking questions. I have had ChatGPT send me down a rabbit-hole because it assumed my spelling mistake was correct.

Potential incompatibility between running MailEnable on Windows Server 2022 and Malwarebytes Premium

Just a heads-up for anyone running MailEnable Enterprise Premium on Windows Server 2022 and Malwarebytes Premium…

We recently installed Malwarebytes to enhance security on your MailEnable mail server. I have always been happy with Malwarebytes and highly recommend it as security software on desktop PCs. However, after recently installing Malwarebytes Enterprise Premium, we’ve experienced a number of issues.

Firstly, the MailEnable IMAP service would go down, and some connections to other services would be blocked entirely. After IMAP went down, the host would become sluggish or we’d be unable to connect via RDP.

Finally, the host would crash entirely and all services would go down.

We are not certain yet of the exact cause, but we know that this problem started happening after we installed Malwarebytes and ended immediately after we uninstalled and did a Windows reboot.

The details are here:

Edition:	Windows Server 2022 Standard 64-bit
Version: 	21H2
OS build: 	20348.2340

MailEnable Enterprise Premium 
Version 10.48

Malwarebytes Premium 
File version 5.1.1.82

If you are experiencing problems running the two MailEnable and Malwarebytes together on Windows Server 2022, it could be because there’s a conflict and it’s worth uninstalling Malwarebytes to troubleshoot.

A Linux Bash script to sync the most recent version of a file on a remote host to a local host (using SFTP) and a password

This bash script will log in to a remote host using SFTP, find the most recently modified file in a directory, and download it to a specified local directory.

#!/bin/bash

datestamp=$(date +%Y-%m-%dT%H:%M:%S%z)
echo $datestamp

fileName=$(echo "ls -1rt" | sshpass -p PASSWD sftp user@host | tail -1)

echo "Latest file is: " $fileName

echo "lcd /the/local/target/directory/to/place/downloaded/file
get $fileName targetfilename.txt" | sshpass -p PASSWD sftp user@host

echo "-----"
echo ""

This script uses sshpass. Sshpass is a utility you can use to pass along a password to an ssh prompt when using a key is not feasible. It’s great for scripts. Just make sure that the script which contains your password is not world readable.

n.b. This script works on the default directory on the target machine. If you want to change directories on the remote host, you’ll need to echo a “cd /your/path/here” before the “lcd” statement.

The script was written to facilitate logging, which is why it has echo statements echoing the datestamp, filename of the file which is being retrieved, and separator markers.


  • You’ll need to update the script to replace user@host with the username and hostname of the user which has SFTP access to the remote host.
  • You’ll need to update PASSWD with the cleartext password of the above user.
  • Replace targetfilename.txt with the filename you want the downloaded file to have after you’ve downloaded a copy. If you want the same filename (no name change), then remove targetfilename.txt altogether.
  • And finally, replace ‘/the/local/target/directory/to/place/downloaded/file‘ with your target directory for where to download the file locally.

Set the script to run via cron at the appropriate times. Pipe the output using &>> to append all output (standard out and err) to the log file. e.g.

/usr/local/sbin/syncscript.sh &>> /var/log/syncscript.log

How to manually set up GeoIP geolocation using MaxMind and without using a package manager

GeoIP is the process of determining a geographic location of a requestor based on an IP address.

On many Linux systems, like Centos, Debian or Ubuntu, you can install an Apache mod called mod_geoip, which you can then use either within your Apache stanza config, .htaccess or within PHP by calling a function with the IP as an argument.

In this tutorial, I will briefly show you how to set up GeoIP using MaxMind Reader and GeoLite2 Free Geolocation Data.

You will need two things:

  • The MaxMind Reader class, which is free to download and available from here. You can download the whole project as a Zip file. If you’re on the command-line, you can right-click on the green link to grab the URL. At the time of writing, it was here.
  • The GeoLiteIP database from MaxMind. GeoLite2 Database is located here, and is free. Unfortunately, you will need to register first to download it. The download page is here, and in this example we’ll use the ‘GeoLite2 Country’ binary database which has the file extension .mmdb

Download the MaxMind project folder and put it in a subfolder of the PHP page from which it will be needed. Let’s say we have an index.php page which is at the document root, which has the path /var/www/public_html/mywebsite/index.php. Your unzipped folder of MaxMind will be named: MaxMind-DB-Reader-php-main. Rename it ‘MaxMind’.

Inside the MaxMind project folder should be a file called ‘autoload.php’ and a subfolder named ‘src’.

Next, download the GeoLite2 .mmdb Country database. By convention, this should go in the: /usr/share/GeoIP/ folder or subfolder, but you can put it wherever you like.

We can now add some code to our index.php page to use the MaxMind libraries and perform a GeoIP lookup.

First, load the autoloader in the MaxMind folder. Next you need the ‘use‘ keyword to use to declare the namespace. Third, create a variable pointing to the MaxMind database you just downloaded. Finally, instantiate a reader of the MaxMind Reader class:

require('MaxMind/autoload.php');
use MaxMind\Db\Reader;
$databaseFile = "/usr/share/GeoIP/GeoLite2-Country.mmdb";
$reader = new Reader($databaseFile);

Once you’ve done those four things, you’re ready to look up the geo-location of an IP.

If you want to test for a proxy IP (HTTP_X_FORWARDED_FOR), then I suggest you use the following code:

if (getenv('HTTP_X_FORWARDED_FOR')) {
        $pipaddress = getenv('HTTP_X_FORWARDED_FOR');
        $ipaddress = getenv('REMOTE_ADDR');
        //echo "Your Proxy IP address is : ".$pipaddress." (via $ipaddress)";
} else {
        $ipaddress = getenv('REMOTE_ADDR');
        //echo "Your IP address is : $ipaddress";
}

After that, you can call the reader class to do a lookup:

if (isset($pipaddress)) {
        $geoip_array = $reader->get($pipaddress);
} else {
        $geoip_array = $reader->get($ipaddress);
}

The reader class will return an array of different information you can use. Here is an example of a print_r statement on the $geoip_array variable on a test page accessed by a Tor Browser:

Array
(
    [continent] => Array
        (
            [code] => EU
            [geoname_id] => 6255148
            [names] => Array
                (
                    [de] => Europa
                    [en] => Europe
                    [es] => Europa
                    [fr] => Europe
                    [ja] => ヨーロッパ
                    [pt-BR] => Europa
                    [ru] => Европа
                    [zh-CN] => 欧洲
                )

        )

    [country] => Array
        (
            [geoname_id] => 2750405
            [is_in_european_union] => 1
            [iso_code] => NL
            [names] => Array
                (
                    [de] => Niederlande
                    [en] => Netherlands
                    [es] => Holanda
                    [fr] => Pays-Bas
                    [ja] => オランダ王国
                    [pt-BR] => Holanda
                    [ru] => Нидерланды
                    [zh-CN] => 荷兰
                )

        )

    [registered_country] => Array
        (
            [geoname_id] => 2750405
            [is_in_european_union] => 1
            [iso_code] => NL
            [names] => Array
                (
                    [de] => Niederlande
                    [en] => Netherlands
                    [es] => Holanda
                    [fr] => Pays-Bas
                    [ja] => オランダ王国
                    [pt-BR] => Holanda
                    [ru] => Нидерланды
                    [zh-CN] => 荷兰
                )

        )

    [traits] => Array
        (
            [is_anonymous_proxy] => 1
        )

)

If you just want the Country ISO code, for example, you can use the code:

$geo_location = $geoip_array['country']['iso_code'];

Recovering an Admin account in WordPress using the command line

So, you’ve decided to lock yourself out of your WordPress admin account. Don’t worry, if you have shell access to your files there are a few ways you can recover and admin account or make a new one. I will show you two of them here.

Assuming your IP hasn’t been blocked by a plugin, or you’ve otherwise broken the WP login procedure, you can use one of the two methods to either create a new account or reset the password of an existing account:

1. Edit your functions.php file so that it will automatically create a new admin account for you when it loads.

Following this code:
https://stackoverflow.com/questions/17308808/create-an-admin-user-programmatically-in-wordpress

function rndprfx_add_user() {
    $username = 'username123';
    $password = 'azerty321';
    $email = 'example@example.com';

    if (username_exists($username) == null && email_exists($email) == false) {
        $user_id = wp_create_user( $username, $password, $email );
        $user = get_user_by( 'id', $user_id );
        $user->remove_role( 'subscriber' );
        $user->add_role( 'administrator' );
    }
}
add_action('init', 'rndprfx_add_user');

Copy and paste the above in your functions.php WordPress file (make a backup first). This file is located in wp-includes WordPress folder.

You will need to replace the variable assignments for $username, $password, and $email above once you’ve pasted in the code. Once you’ve logged in successfully once, remove the code from your functions.php file.

2. Use wp-cli to edit the password of an existing admin account

In case you’re not already using it, you should familiarize yourself with wp-cli.

WP-CLI is the command-line interface for WordPress. You can update plugins, configure multisite installations and much more, without using a web browser.

https://wp-cli.org/

It’s a very handy tool for administering a WordPress site via the command line and can be used to write scripts to automate tedious or periodic WP tasks.

The full list of wp-cli commands can be found here:

https://developer.wordpress.org/cli/commands/

Install wp-cli using the instructions on the wp-cli homepage, or use yum or your OS’s favourite package manager.

Go to the root directory of the WordPress installation. This is the public_html or similarly named folder which contains the wp-config.php file for your WP installation.

You will now need to be either the user who has ownership of the WordPress folder and files, or be root. If you are root, you can use the: ‘–allow-root’ argument to allow wp-cli to run as root. The wp-cli command gives you a warning about running as root because, like every other command run as root, it will have access to all files on the server.
Be careful about updating plugins as root, since the file permissions for the plugin will change.

We will continue this tutorial as root. Run the command:

wp --allow-root user list

To show you the list of users, including their login, display name, email, when they registered, and their role (access level). Admins have the role ‘administrator’.

From there, you can use:

wp --allow-root user update id --user_pass=password

…to update an admin user’s password by id. Id and password above are variables you need to replace.

Or alternatively:

wp --allow-root user update username --prompt=user_pass

Where username is the variable you need to replace. You’ll be prompted to enter a new password at the command line. You are only asked once, so be sure to test login.

How to build a Nagios plugin using a simple example

A Nagios plugin can be built using practically any language. There are only a few requirements:

  1. A set of one or more inputs (parameters) which the Nagios server will send in order to give it essential information to operate (such as which host to monitor, thresholds, etc.)
  2. Text output of the program, showing the result of the check. The first line will be shown in the services preview of the host in the Nagios web interface. Clicking in to the service will show all of the output.
  3. An exit code returned by the plugin program to indicate the results of the check. That is, the current state of the plugin. This will be: “OK”, “Warning”, or “Critical”.

The text below is an example plugin written in Bash which scans a host using nmap and tests the result against a known MD5 hash of the expected output. If the status of any of the ports change, then the MD5 hash will change and return a ‘CRITICAL’ state.

The output of the nmap scan and the hash are printed out by the plugin in all cases and is available by clicking on the service in the web interface.

#!/bin/bash

NMAPOUTPUT=$(nmap -oG - $1 | grep "Ports")

NMAPOUTPUTHASH=$(echo $NMAPOUTPUT | md5sum | cut -d ' ' -f 1)

if [ $NMAPOUTPUTHASH == $2 ]; then
        echo "OK: Hash of nmap portscan consistent."
        STATUS=0
else
        echo "CRITICAL: Hash of nmap portscan inconsistent."
        STATUS=2
fi

echo $NMAPOUTPUT
echo $NMAPOUTPUTHASH

exit $STATUS

This plugin is run using two parameters: hostname and md5sum. In bash, $0 is the name of the program which is being run. $1 is the first parameter, here the hostname. $2 is the second parameter, here the md5sum.

Nagios will interpret the exit status of the plugin as the state of the plugin check. All plugins will return with an exit code of 0, 1, or 2. These correspond to: “OK”, “Warning”, and “Critical”, respectively.

Here is a useful guide on how to configure Nagios to use a new plugin you just wrote:

An interesting exchange with Chat GPT regarding predicting Bitcoin price

Q: Historically, what is the most reliable and accurate leading indicator of future Bitcoin price?

A: Historically, the most reliable and accurate leading indicator of future Bitcoin price has been the Google Trends search volume for the term “Bitcoin”. This is because the search volume is a good indicator of the level of public interest in Bitcoin, which is often a good predictor of future price movements.

Q: Is that a leading indicator?

A: Yes, Google Trends search volume for the term “Bitcoin” is a leading indicator of future Bitcoin price.

Q: Approximately what time period does it lead?

A: The Google Trends search volume for the term “Bitcoin” typically leads the Bitcoin price by a few weeks to a few months.

Q: Can you provide an r-value for the correlation between Google Trends search volume for term “Bitcoin” and Bitcoin price? The correlation between Google Trends search volume for the term “Bitcoin” and Bitcoin price is typically around 0.7, indicating a strong positive correlation.

Sorting a list of CIDR IP addresses

You may have a list of IP addresses which follow CIDR format, i.e. 111.12.23.45/16 and which you wish to sort. Here is an algorithm to do so in Microsoft Excel:

Step 1. Paste all IP addresses in to a single column A in your Excel sheet.

Step 2. Remove the CIDR part of the IP address in column A by applying the following formula to the first row in Column B:

=LEFT(A1,FIND("/",A1)-1)

This will turn an IP address, such as 111.12.23.45/16 in to 111.12.23.45.

Step 3. Once you get a valid IP address in Column B, double click on the bottom-right corner of the cell to propagate for formula to the rest of the rows in Column B.

Step 4. Select the entire Column B and then paste again using Paste Special… Values. This will remove all the formulas and retain only the IP values.

Step 5. Apply the following formula in Column C in order to make sure each octet of your IP address has three digits:

=TEXT(LEFT(B1,FIND(".",B1,1)-1),"000") & "." & TEXT(MID(B1,FIND( ".",B1,1)+1,FIND(".",B1,FIND(".",B1,1)+1)-FIND(".",B1,1)-1),"000") & "." & TEXT(MID(B1,FIND(".",B1,FIND(".",B1,1)+1)+1,FIND(".",B1, FIND(".",B1,FIND(".",B1,1)+1)+1)-FIND(".",B1,FIND(".",B1,1)+1)-1), "000") & "." & TEXT(RIGHT(B1,LEN(B1)-FIND(".",B1,FIND(".",B1,FIND( ".",B1,1)+1)+1)),"000")
[*] https://www.extendoffice.com/documents/excel/4946-excel-sort-ip-address.html

This will convert all your IPs (without CIDR notation) in to a set of numbers with the following format: XXX.XXX.XXX.XXX. That is to say, each octet will contain exactly three digits. In cases where an octet originally has only two digits, then a zero will be prepended. In the case where the octet originally has only one digit, then two zeros will be prepended.

For example, our original IP: 111.12.23.45/16 will now look like: 111.012.023.045

Step 5. Apply the same thing you did in Step 4. but to this new column C, so that only the values remain.

You should now have three columns in your Excel sheet. The first column is a list of your original IPs in CIDR format. The second is a list of the same IPs without the CIDR notation. The third is a list of the same IPs where each octet has precisely three digits.

Step 6. The final step is to sort the list by column 3: Select the whole sheet by clicking on the top-right corner of the sheet where the rows and columns meet. Go to Menu Item: ‘Data’… click on the ‘Sort’ icon, and select Column 3.

One caveat for using this algorithm:

This algorithm does not take into account the CIDR values when sorting.