Category Archives: IT & Tech

Interesting stuff from the world of bits, bytes and hardware.

WordPress: new editor “Invalid JSON response” on Ubuntu 22.04 — what it means and how to fix it.

In the world of cryptic and rather unhelpful error messages, “invalid json response” when trying to save & update a post or page in wordpress’ new editor runs a close second to my all time favourite “invalid shared memory realm” from Oracle’s absysmal overhyped, and overly expensive database stuff.

So what do you have to do? Simple:

o become “root”

o edit /etc/apache2/apache2.conf using the editor of your choice (nano, emacs, …)

o find the section for /var/www

o Change “AllowOverride None” to “AllowOverride All”

o make sure mod_rewrite for apache is installed and enabled (a2enmod rewrite)

o reload the apache config using systemctl reload apache2

That’s it, switching to SEO-friendly permalinks in Settings -> permalinks on your wordpress site should no longer break making changes to posts / pages and saving them.

Oh yeah, I think I left out the “what it means” part, but hey, I guess you can come up with an explanation of your own 🙂

ffmpeg: cut movie at beginning and end, scale it quickly

ffmpeg -ss 565 -to 01:56:40 -i input.mpg -c:a copy -c:v libx264 -crf 18 -preset ultrafast -s 1280x720 -pix_fmt yuv420p -map 0:a? -map 0:v -ignore_unknown output.mkv

Explanation:

-ss 565: cut the first 565 seconds (time format can also be used I think)

-to 01:56:40: cut the movie at 1h56m40secs, discarding the rest

-crf 18: Higher values: smaller file, worse quality; lower values (e. g. 10): bigger file, higher quality.

-i input file

The resulting scaled file will be written to “output.mkv”.

Source:

https://superuser.com/questions/1527662/visually-lossless-1080p-to-720p-using-ffmpeg

fix HDXRTME_install.sh script in order to install on Linux Mint

Installation of the HDX RealTime Media Engine 2.9 for Microsoft Skype for Business on Linux Mint not working? See below to see what needs changing in the install script.

grep -n LinuxMint HDXRTME_install.sh

1289: "LinuxMint" | "Ubuntu" | "ThinPro" | "Debian")
1447:if [ "$os" != "Ubuntu" ] "$os" != "LinuxMint" ] && [ "$os" != "RedHat" ] && [ "$os" != "ThinPro" ] && [ "$os" != "Debian" ]; then
1468: "Ubuntu" | "LinuxMint" | "ThinPro" | "Debian")
1542: "Ubuntu" | "LinuxMint" | "ThinPro" | "Debian")
1594: "Ubuntu" | "LinuxMint" | "ThinPro" | "Debian")

Change the lines above in the original install script to add Linux Mint support during installation.

Using Elgato’s Stream Deck XL on Linux with streamdeck_ui

I got myself a lovely streamdeck XL and had some issues getting it to work with streamdeck_ui on Linux Mint 20. It turned out that the usual howtos don’t include the Device id required for the XL model which is 008f, so simply add the following line to your udev rules:

SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="008f", TAG+="uaccess"

reload the udev rules as per howto, replug the device, now streamdeck_ui should have no issues attaching to the HID device when running as a normal user without root permissions.

Unplugging & replugging

Watch Disney+ on Linux chrome based browsers (in 2022)

o Install this extension from the chrome webstore:

https://chrome.google.com/webstore/detail/user-agent-switcher/aedikcfpfonanffanecfolneiaoakmlc

o when using disney plus, right-click on the page and select “Microsoft Edge / Windows” as your user agent

o once you’re finished with Disney Plus, revert back to “default” as to not ruin Linux browser statistics on other web sites 🙂

PS: No guarantees, it worked for me in Chromium and Vivaldi. If you’re worried, please use a standalone chrome / chromium install exclusively to watch Disney Plus on your trusty Linux system using only the above extension for viewing.

Extracting google authenticator accounts for use with keepass TOTP-plugin

If you want to use an existing google authenticator account for use with keepass, the process to extract the base32 seed required by Keepass’ TOTP plugin can be quite involved.

So for posterity, I’ve documented the process here (I am using a company provided iphone and an Ubuntu Linux VM, but I think the process will be quite similar for android systems and other Linux distributions).

If you have any questions, feel free to leave a comment!

Open the google authenticator app on your phone

Select “export” from the hamburger menu

uncheck all accounts & re-check the one you want exported (make sure you don’t accidentally delete the original account on your phone :))

save the generated QR-code (jpg or png) to your photos or wherever & copy it to your Linux machine (I used telegram’s very handy “Saved Messages” feature for this)

install the “zbar-tools” package using apt or apt-get

o clone this git repository:

git clone https://github.com/scito/extract_otp_secret_keys

change to the newly created directory:

cd extract_otp_secret_keys

o extract information from the qr code image (using test.jpg as an example)

zbarimg test.jpg > test.txt

o edit test.txt, remove the leading “QR-Code:” string

o use pip to install the packages protobuf & qrcode:

pip install protobuf==3.20.1 qrcode # use this version as later versions won't work as of this writing

o extract the keys:

python3 extract_otp_secret_keys.py -p test.txt

Use the string labelled “Secret” as the “base32” TOTP-Secret in keepass2

That’s it! From now on, you should be able to generate TOTP tokens even if you just dropped your mobile into the toilet (it happens :))

apache2 basic auth / ip based authentication

As I keep forgetting how this works, here’s an example config that will require basic auth for the “/” URI while permitting basic-authless access to “/test” for IPs listed in the Allow from statement (other source IPs will still be able to access stuff in “/test” if proper basic authentication info is provided with the request):

# httpd.conf 

# basic auth für "/" und "/test" except for IPs listed in the "Allow from..." Statement 

<Location /> 

   AuthType Basic 

   AuthUserFile /etc/httpd/conf/htpasswd 

   AuthName "Authorized Users Only" 

   require valid-user 

</Location> 

<LocationMatch /test/*> 

   Order Deny,Allow 

   Satisfy any 

   Deny from all 

   Require valid-user 

   Allow from AAA.XXX.YYY.ZZZ 

</LocationMatch> 

Changing the default sound output device in Counterstrike: Global Offensive (on Linux)

I know I’m about 10 years late to the party, but I recently picked up “Counter Strike: global offensive (“csgo” for short) on Linux when I found out the title was now free to play on steam.

My distro of choice is Linux Mint 19.2 and getting the game to run itself on Linux was not a big issue thanks to using modern drivers for my nvidia gtx1070ti, however no matter what I tried, csgo would insist on playing its ingame sound (both effects & VOIP) on my external speakers (when everybody knows you need a proper headset to fully enjoy the 3d effects the game provides).

After a lot of googling I finally found a workaround which involves some pulseaudio (PA) hacking, but seems to work ok in a reliable and repeatable manner.

The basic principle is that you redirect csgo’s sound output (a “sink” in PA lingo), after it’s been created,to the sound device of your choice.

You’ll need to alt-tab out of the game once it’s started but I’ve found the function is rather stable if you run csgo in “fullscreen windowed” mode.

Once csgo is running, alt-tab to a 2nd virtual desktop and open a shell.

In this new shell, we’ll need to determine the current index / id of the headset like so:

$ pactl list short sinks
0 wave_output modules/module-waveout.c s16le 2ch 44100Hz RUNNING

(the above is just an example as I’m typing this on a Linux VM). The number we need is the “0” in this case, choose this according to the index number where your headset is displayed in pactl’s output.

Next, we create a simple shell script (need to to this only once of course) with the following content, calling it “movesinks.sh” or similar:

#!/bin/bash 
echo "Setting default sink to: $1";
pacmd set-default-sink $1
pacmd list-sink-inputs | grep index | while read line
do
echo "Moving input: ";
echo $line | cut -f2 -d' ';
echo "to sink: $1";
pacmd move-sink-input `echo $line | cut -f2 -d' '` $1

done

(Source: https://askubuntu.com/questions/71863/how-to-change-pulseaudio-sink-with-pacmd-set-default-sink-during-playback)

I’ve chosen $HOME/bin/movesinks.sh as my location for this script, but you can put that wherever you want as long as the directory is in your PATH.

Once you have that script at the ready and executable (chmod 755 ~/bin/movesinks.sh in my case), simply type

movesinks.sh <indexnumber>

where the <indexnumber> is the number that is displayed for your headset in the pactl output listed above.

Now you can cycle back to the virtual desktop that csgo is running on, hit alt-tab there and hey presto!, csgo should now be outputting its sounds to your headset.

Thanks to “Zanna” over at askubuntu.com for the original script!

Restoring the GRUB boot sector on Linux Mint 19 / Ubuntu 18.04

 



Note to self: Always make a copy of your boot sectors using dd first. 
Note to world: These commands will only work if you have a separate boot partition. 



# take note of your Linux partitions (/dev/sde3 == /, /dev/sde1 = /boot in my case)

fdisk -l 

# Mount Linux partitions using your live installer cd / usb key: 

mount /dev/sde3 /mnt
mount /dev/sde1 /mnt/boot

# re-install grub to /dev/sda

grub-install --boot-directory=/mnt/boot /dev/sda 

Source(s):
https://help.ubuntu.com/community/Grub2/Installing

 

Updating Lineage OS 14.1 on a Samsung Galaxy S3 (GT-9300i)

While lineage claims that the update process is mostly automatic on the Galaxy S III (gt-9300i), I found that after downloading an update and rebooting I ended up in my TWRP boot screen, with nothing much automatic going on at all.

It took me a while to determine the storage location of the downloaded updates (that much worked I’m happy to report), and it seems that for me (LineageOS 14.1) they end up on the internal SD card in a directory called

/data/lineageos_updates

 

The trick was to use the “up one level” function in TWRP’s image selection to actually see the root level of the internal SD card.

 

Then, all I needed to do was to select the most recent update (it’s in zip format so you may need to switch the image / zip display in TWRP’s “install” screen, flash it (apparently you don’t have to wipe the cache for it to work), reboot the system and wait about 15 minutes, and hey presto!, here’s my most recent Lineage OS update running fine on my S III.

Caveat: During the initial migration from CM13 to Lineage 14.1, I found the system would not boot properly if I chose to select the “SuperSU” package as offered by the Lineage OS installer. Not choosing to install that package would allow the system to boot properly.

I hope this helps you updating and keeping current your beloved GT-9300i phone!

Increasing the number of open files for MariaDB 10.1 on CentOS7 (openstack pike RDO install)

(c) stackhpc

Our openstack pike installation crashed after a couple of days with tons of error messages in /var/log/mariadb/maria.log in the form of

Error in accept: Bad file descriptor

Some googling  hinted at mariadb running out of open files, but I had some problems getting to grips how to set the number of open files for mariadb 10.1.20 (used by the rdo openstack-pike) on a CentOS 7 system, so here’s for posterity:

1)increase the ulimit in /etc/security/limits.conf as usual:

* hard nofile 1024000
* soft nofile 1024000

2) create the file (if it doesn’t exist, otherwise edit the existing file) /etc/systemd/system/mariadb.service.d/limits.conf 

and add the following lines

[Service]
LimitNOFILE=1024000

2a) reload systemd

# systemctl daemon-reload

3) restart mariadb

# systemctl restart mariadb.service

4) check the results

# mysql -pXXXXXXXX mysql

MariaDB [mysql]> show global variables like 'open%';
+------------------+---------+
| Variable_name | Value |
+------------------+---------+
| open_files_limit | 1024000 |
+------------------+---------+
1 row in set (0.00 sec)

5) Enjoy a hopefully crash-free OpenStack Pike setup 😉

 

Setting up & running letsencrypt a.k.a. certbot on CentOS / RHEL 5 systems

 

Getting letsencrypt to run on an ancient CentOS  or Red Hat Enterprise Linux 5 system (they still tend to appear in the wild from time to time) can be a major headache. I took some notes during the setup, I hope you find the useful (you'll need some basic Unix admin skills in order to follow this recipe, so caution is advised as you go through the procedure). 

Sources: 

http://stackoverflow.com/questions/23548188/how-do-i-compile-python-3-4-with-custom-openssl



Important: You'll need to use Python 2.7.8, anything beyond that version will
die with an invalid certificate error during the certbot setup phase. 



# compile openssl from source:

mkdir -p /server/src && cd /server/src

wget https://www.openssl.org/source/openssl-1.0.1t.tar.gz


tar xvzf openssl-1.0.1t.tar.gz && cd openssl-1.0.1t

./config --prefix=/server/openssl-1.0.1t shared --openssldir=/server/openssl-1.0.1t/openssl


make depend && make && make install

# create a softlink for convenience 

ln -s /server/openssl-1.0.1t /server/openssl

# Get Python 2.7.8

cd /server/src && wget https://www.python.org/ftp/python/2.7.11/Python-2.7.8.tgz


tar xvzf Python-2.7.8.tar.gz

cd python-2.7.8

# set up compile environment

export LDFLAGS=-"Wl,-rpath=/server/openssl/lib -L/server/openssl/lib -L/server/openssl/lib64/"

export LD_LIBRARY_PATH="/server/openssl/lib/:/server/openssl/lib64"

export CPPFLAGS="-I/server/openssl/include -I/server/openssl/include/openssl"

./configure --prefix=/server/python-2.7.8

make && make install

# create softlink, adjust PATH

ln -s /server/python-2.7.8 /server/python; export PATH=/server/python/bin:$PATH

# install pip in new python version

wget --no-check-certificate https://bootstrap.pypa.io/get-pip.py

python2.7 get-pip.py

# install virtualenv, wheel

pip install virtualenv wheel

# git-clone certbot (latest version)

 cd /server/src/ ; git clone https://github.com/certbot/certbot

# Request a certificate manually (certonly)

cd certbot; ./letsencrypt-auto certonly --manual -d my.server.tld 

# configuring your webserver of choice is left as an exercise for the reader.

 

VBulletin keyboard navigation (a bit half-****, but works)

 

I really don’t like web forums all that much, I think they all suck in one way or another and I really yearn for the good old USENET days when everybody was free to use their reader of choice… well, those were the days.

 

With “vBulletin” being a vey prolific and widespread software for many forums / fora / forae I visit regularly, I wanted to bring some comfort back to browsing them by adding some simple keyboard navigation using some javascript I freely “borrowed” from the web sites out there.

 

Here’s the result:

 

“n” – Search for new posts

“g” – go to the first post in the list of new posts

“j/k” – navigate forward / backward in the pages of a thread and / or search results

Cut & Paste the script below and save it to a location of your choice, then you can use the  “tampermonkey” extension for Chrome and other browsers to enable these features (chrome stopped accepting non-store based extensions a year ago for whatever reasons they saw fit, tampermonkey helps to get chrome back under the user’s control)

Add the URLs of your favourite forums to the script and import it into tampermonkey (some niftier form of configuration may be on the cards, but I’m lazy so feel free to add it yourself if you want to).

I hope you find this script useful, enjoy keyboard navigation in vB! 😉

VBB “What’s new” user Script

// ==UserScript==
// @name VBB Show new posts
// @namespace http://www.schuerkamp.de/greasemonkeyhacks/
// @description Adds a "whats new" search link and some shortcuts to vbb forum pages
// @description Download URL: http://dl.dropbox.com/u/1983539/isi_whatsnew.user.js
// ##### ADD THE URL of your vB forums below ##################
// @include http*://*isiforums.net/*
// @include http*://*www.bmsforum.org/*
// 
// ==/UserScript==

var EuropeanDateFormat=1; 
var newlink = document.createElement('a');
var todays_posts = document.createElement('a');
newlink.href = 'search.php?do=getnew&contenttype=vBForum_Post';
todays_posts.href = 'search.php?do=getdaily&contenttype=vBForum_Post';
tn = document.createTextNode(' Show new posts ');
newlink.appendChild(tn);
tn2 = document.createTextNode(' Show todays posts');
todays_posts.appendChild(tn2);

var footer = document.getElementById('footer_links');

if (footer) {
 footer.appendChild(newlink);
 footer.appendChild(todays_posts); 
}

// quick hack to set a default email address
from = document.getElementById('it_from_3');
if (from) {
 from.value="beta-applications@imagespaceinc.com"; 
}

if (EuropeanDateFormat == 1) {
 var dates = document.getElementsByClassName('date');
 for (var i = 0 ; i < dates.length ; i++) {
 var post_date = dates[i].innerText;
 // check if there's a year string in the -2012 notation (will stop working in 2100 ;-) 
 if (post_date.indexOf("-20") != -1 ) {
 year = post_date.substring(6, 10);
 month = post_date.substring(0, 2);
 day = post_date.substring(3, 5);
 var new_date = ""; 
 dates[i].innerText = year + "/" + month + "/" + day; 
 }
 } 
}

// stolen shamelessly from userscript.org's facebook key navigation
// Thanks to Droll Troll

function OnKeyUp(e)
{
 var anchors = document.getElementsByTagName('a');
 for (var i = 0 ; i < anchors.length ; i++) {
 var href = anchors[i].getAttribute('href'); 
 if (href) {
 if(href.match(/goto=newpost/)) {
 break ; 
 }
 }
 } 

 // do a search if we cannot find the "next page" link
 next_page_or_new ="search.php?do=getnew&contenttype=vBForum_Post"
 for (var i = 0 ; i < anchors.length ; i++) {
 var next_page_href = anchors[i].getAttribute('href'); 
 var title01 = anchors[i].getAttribute('title'); 
 if (title01) {
 if(title01.match(/Next Page/)) {
 next_page_or_new = next_page_href
 break ; 
 }
 }
 } 

 prev_page_or_new ="search.php?do=getnew&contenttype=vBForum_Post"
 for (var i = 0 ; i < anchors.length ; i++) {
 var prev_page_href = anchors[i].getAttribute('href'); 
 var title01 = anchors[i].getAttribute('title'); 
 if (title01) {
 if(title01.match(/Prev Page/)) {
 prev_page_or_new = prev_page_href
 break ; 
 }
 }
 } 

 key_map = {
 "N" : "search.php?do=getnew&contenttype=vBForum_Post",
 "G" : href,
 "K" : next_page_or_new, 
 "J" : prev_page_or_new, 
 "T" : 'search.php?do=getdaily&contenttype=vBForum_Post'
 }

 if (String.fromCharCode(e.keyCode) in key_map && 
 (typeof e.target.type == "undefined" || (e.target.type != "text" && e.target.type != "textarea")) && 
 !e.altKey && !e.ctrlKey && e.keyCode <= 90)
 {
 window.location.replace(key_map[String.fromCharCode(e.keyCode)])
 }
}

window.addEventListener("keyup",function(event) { OnKeyUp(event); },false)