Monday, 16 March 2020

Substitution for Microsoft's Calibri and Cambria fonts in LibreOffice

I know that there are many people out there who get very disappointed when they use LibreOffice for the first in order to open a document created with MS-Office and then see that the layout of the document getting ruined. One of the reasons why this is happening is the absence of the famous Calibri and Cambria fonts that as Wikipedia puts it ...

Calibri is also distributed with Microsoft Excel Viewer, Microsoft PowerPoint Viewer, the Microsoft Office Compatibility Pack for Microsoft Windows and the Open XML File Format Converter for Mac. For use in other operating systems, such as cross-platform web use, Calibri is licensed by Ascender Corporation and its parent company Monotype Imaging.

Things could get more complicated especially if you use any MS font in a book and anything printed without licence but once again there is a workaround ...

In 2013, due to Calibri's widespread use in Microsoft Office documents, Google released a freely-licensed font called Carlito, which is metric-compatible to Calibri, as part of ChromeOS.[21] Because Carlito has the same font metrics as Calibri, ChromeOS users can correctly display and print a document designed in Calibri without disrupting layout. Carlito’s glyph shapes are based on the prior open-source typeface Lato, without de Groot's involvement.

To finish the story from the Cambria's side

Caladea
In 2013, as part of Chrome, Google released a freely-licensed font called Caladea, which is metric-compatible to Cambria (i.e. can replace it in a document without changing the layout).[10] It is based on Cambo, a font developed by the Argentine type foundry Huerta Tipográfica. Despite being metric-compatible, Caladea covers much smaller language range, e.g. it doesn't support Cyrillic, Greek and advanced typographic features like ligatures, old style numerals or fractions.

Carlito can be downloaded from here, while Caladea from here. After theses fonts are installed on your system, open any LibreOffice program, click on Menu Tools and then select Options. Open the "Font Replacement" page of the options dialogue and fill it like this.

Friday, 8 November 2019

Auto allocation of spice TLS ports requested but spice TLS is disabled in qemu.conf

I am not sure why this happens. My best guess is that there is some kind of address or port mangling. So you just a created a VM using libvirt/qemu in LTS Ubuntu 18.04 and you want to change spice options in order to access the VM with an other tool like remmina..

This does not happen always, But in my experience. it always happens when the VM nic is connected to the QEMU internal NAT, and you try to specify a custom spice port. If you use bridging and then link the virtual machine's network card to the host machine's bridging interfaces, chances are that the virtual machine will start normally.

The next thing that worked for me was to tamper with the VM's settings using the virsh generated XML file. So log in the host machine and asyming that you vm's name is my-vm, enter the following command

virsh --connecy qemu:///system dumpxml my-vm > my-vm.xml

This will create a my-vm.xml xml file. Open it with your favourite text editor and locate the line that starts with graphics. Change it so looks like this:


    <graphics type='spice' port='5901' autoport='no' listen='0.0.0.0'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>

In this case the port number is 5901. Pick your own number. Save the file and then use virsh to apply the changes.

virsh --connect qemu:///system define my-vm.xml

Start the virtual machine with a command like virsh start my-vm or with the graphical Virtual machine manager Tool. In my case, "it" worked afterwards :)

Tuesday, 7 August 2018

How to use the latest PHPOffice/Spreadsheet with CakePHP 2.x

Preface

Using the latest PHPOfficePhpSpreadsheet in a CakePHP3 application is relatively easy, A simple composer command like composer require phpoffice/phpspreadsheet does the trick in a few seconds and then you ready to go.

All of as Cake uses end up with a PHPExcelComponent that we either borrow or devise ourselves, so we can make our users ... happy by giving them the beloved excel files.

The problem with using PHPOffice/PhpSpreadsheet inside a CakePHP2 application is that CakePHP2 does not support namespaces and so the App::import() is not able to load all the required classes correctly.

This simple howto lists all the steps that I followed in order to make things work, with the help of this question at stackoverflow and this blog post from Mark.

The Steps

  1. Download the latest version from here.
  2. Extract the zip file and rename the src folder (inside Phpspreadsheet-develop) to PhpOffice
  3. Go to your Cake2 project and move/copy this new PhpOffice folder inside your APP/Vendors folder
  4. While you are there, create another folder named Psr (inside your APP/Vendors) and an other folder named SimpleCache inside Psr. (You will know why in a minute)
  5. PhpSpreadsheet refferences the Fig-Simple cache library that we also have to install manually. Go to the php-fig/simple-cache page and download the required zip file (name is simple-cache-master.zip).
  6. Unzip that in a temprary directory and move all three files from the src folder to APP/Vendors/Psr/SimpleCache.
  7. Open your APP/Config/bootstrap.php file and place the following code at the end.
        /**
         * Configure the autoloader
         */
        spl_autoload_register( function($class) {
            foreach(App::path('Vendor') as $base) {
                $path = $base . str_replace('\\', DS, $class) . '.php';
                if (file_exists($path)) 
                    return include $path;            
            }
        }, true);
    
  8. That's it. If you want to use the Spreadsheet class, all you have to do is place a use PhpOffice\PhpSpreadsheet\Spreadsheet; statement at the top of your file and then any reference like _xls = new Spreadsheet(); will work just fine.

A few afterwords

What we actually accomplished here is that we instructed the php class loader to search for any class it does not know about inside a speciffic sub folder of our APP/Vendors. This subfolder structure, must confirm to the exact package name of the class. Hence we created the PhpOffice/PhpSpreadsheet and Psr/SimpleCache subfolders. Using this technique we may add any additional library into our CakePHP2 application provided that we keep this naming standard. My setup was a CentOS 6.10 web server with PHP 5.6.37 (from Remi).

Once again, CakePHP3 and composer can make this job extremely easier, so unless you really have to, do not go into all this fass ;)

Friday, 30 March 2018

JPA Calling a MySQL stored function

I have a stored function called getNextCode() that requires a string parameter and returns a string. I wish to call this from my JPA enabled application. T he following code fragment shows the use of the crateNativeQuery() method to achieve this.


    private String _getNextRollPackageCode()
    {
        String query = String.format(
                "SELECT getNextCode( '%s')",
                this.ROLL_PACKAGES_MODEL_NAME
        );

        return this.ROLL_PACKAGE_CODE_PREFIX + "-" +  (String) _entityManager.createNativeQuery(query)
                .getSingleResult();
    }

Wednesday, 28 March 2018

Ubuntu: Setting up an MQTT Server and connecting via SSL

Foreward

This has been a very frustrating story as I was asked to setup an MQTT server that would support -- every IT Manager's pride and joy -- SSL. The setup was quite smooth, thanks to the good people of Digital Ocean. Their post How to Install and Secure the Mosquitto MQTT Messaging Broker on Ubuntu 16.04, explains everything crystal clear.

I also wanted to setup the websockets protocol, so a Javascript client would continue to work. Last but not least be able to programmatically connect using programs written in Java, C# and Python 3. This blog post shows the exact setup we used to make things work, as well as minimal code samples about how to connect.

For the shake of this example, my server DNS name is supposed to be mysite.net, the MQTT server user is mqtt-user and the password we set, is my_Super_Secure_Password.

Server setup and testing

Starting with the setup, I followed Digital Oceans instructions and making a fiew slight changed ended up with this:

# MQTT Config File with websockets and SSL
# Created March - 26th -2018
#

# ----------------------------------------------------------------------------
# Log Setup
# ----------------------------------------------------------------------------
log_type error
log_type warning
log_type notice
log_type information
log_type websockets
websockets_log_level 255
log_timestamp true
# log dest is set in /etc/mosquitto/mosquitto.conf
# web sockets log level can be removed if you verify that websockets is working

# ----------------------------------------------------------------------------
# User Security Setup
# ----------------------------------------------------------------------------
allow_anonymous false
password_file /etc/mosquitto/passwd

# Do not allow non-secure connection from anywhere but the localhost
bind_address    localhost
port            1883

# ----------------------------------------------------------------------------
# This is the SSL Setup
# ----------------------------------------------------------------------------
listener        8883 
protocol        mqtt      

certfile        /etc/letsencrypt/live/mysite.net/cert.pem
cafile          /etc/letsencrypt/live/mysite.net/chain.pem
keyfile         /etc/letsencrypt/live/mysite.net/privkey.pem
require_certificate false

# ----------------------------------------------------------------------------
# Here is our SSL enabled web sockets config
# ----------------------------------------------------------------------------
listener        9993 
protocol        websockets
http_dir        /var/www/mysite.net/mqtt

certfile        /etc/letsencrypt/live/mysite.net/cert.pem
cafile          /etc/letsencrypt/live/mysite.net/chain.pem
keyfile         /etc/letsencrypt/live/mysite.net/privkey.pem
require_certificate false

This is the contents of the /etc/mosquitto/conf.d/default.conf file. To test I switched to my local console and issued the following command:

 mosquitto_sub -h mysite.net -p 8883 -t test -u mqtt_user -P my_Super_Secure_Password --capath /etc/ssl/certs

then opened a second terminal, and each time I would type

mosquitto_pub -h mysite.net -p 8883 -t test -m "Hello Sailor"  -u mqtt_user -P my_Super_Secure_Password --capath /etc/ssl/certs

I would see a Hello Sailor line on the first console screen. That more or less did it

Connecting with Code

This is the part where we completely lost it. All examples in the web show how to perform an SSL connection using your own private key pair but in our case we wanted something much simpler. Our requirement was that the connection be SSL encrypted but we would use the mqtt generated user and password pair. In the Java world, we really got mixed up with keystores, trust manager factories and the like while all it took to post a simple message was :

package com.kfator.mqttclient;

import static java.nio.charset.StandardCharsets.UTF_8;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class Main {
    public static final String MQTT_URL = "ssl://mysite.net:8883";
    public static final String MQTT_USER_NAME = "mqtt_user";
    public static final String MQTT_USER_PASSWORD = "my_Super_Secure_Password";

    public static void main(String args[])
    {
        try {
            MqttClient client = new MqttClient(
                    MQTT_URL,
                    MqttClient.generateClientId(),  // ClientId
                    new MemoryPersistence());       // Persistence

            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, null, new SecureRandom());

            MqttConnectOptions options = new MqttConnectOptions();
            options.setSocketFactory(sslContext.getSocketFactory());
            options.setUserName(MQTT_USER_NAME);
            options.setPassword(MQTT_USER_PASSWORD.toCharArray());

            client.connect(options);
            client.publish(
                "test", // topic
                "Hello from Java".getBytes(UTF_8), // payload
                2, // QoS
                false); // retained?
            client.disconnect();

            System.out.println("Connection established!");
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

The code runs from a Netbenas 8.2 Maven project. To include the paho-mqtt libraries we (sort of) followed the instructions at MQTT Client Library Encyclopedia – Eclipse Paho Java page. the actual steps were to create an empty Mevn Projet, then right click on the dependencies Node, select the add dependency menu item and fill in the form details as show at the begining of the Paho-Java page.

The C# code using the Mqtt-Paho library for .NET goes like this:

    _clientMonitor = new MqttClient("mysite.net", 8883, true, new X509Certificate(), null, MqttSslProtocols.TLSv1_0);

... and finally, python 3 only requires the use of client.tls_set() before calling connect(). Here is the related fragment from out demo program.


client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set(MQTT_USER_NAME, MQTT_PASSWORD)

client.tls_set()
client.connect(HOST, PORT)

And the best part was, that all these worked ...

Tuesday, 22 November 2016

Linux: Verify a burned CD/DVD with the image file used for burning

So I just burned a CD sometime ago and I am not sure if it still works. A quick and easy way to test it's against the original ISO would be to something like this:

thanassis:Downloads/ $ dd if=/dev/sr1 | md5sum                                                                                                                                     [20:46:28]
1366016+0 records in
1366016+0 records out
699400192 bytes (699 MB, 667 MiB) copied, 265,145 s, 2,6 MB/s
d2d939ca0e65816790375f6826e4032f  -
thanassis:Downloads/ $ md5sum ubuntu-16.04.1-server-amd64.iso                                                                                                                     [20:57:07]
d2d939ca0e65816790375f6826e4032f  ubuntu-16.04.1-server-amd64.iso

... and I 'm good to go.

Note: All credit for this solution goes to theSuperusr Community.

Friday, 3 June 2016

Using a raspberry pi (or any Debian based computer) to set up an open VPN server

Why

There are many howto's explaining the set-up of an OpenVPN server. The majority of what I have seen, provide instructions about setting up a tunnel device. This allows you to gain access to the OpenVPN server itself, but requires a lot more customisation if you want to access other computers on the remote LAN.

Using a tap device is much easier, and allows the OpenVPN client to be able to access not only the server but all other computers connected to the same LAN.

The basic idea is that you create an Ethernet bridge on the VPN server. Each time clients connect, the server taps them to that bridge and so clients behave as if they are physically connected to the remote LAN.

How

I would advice starting your setup with a clean fresh install. Before proceeding to follow the instructions below, issue:

pi@gabriella:~ $ sudo apt-get update && sudo apt-get dist-upgrade 

Install the bridge

The first step is to set up our bridge:

pi@gabriella:~ $ sudo apt-get install bridge-utils uml-utilities 

After the bridge-utils package is installed, we need to change the server's network configuration file in order to activate the bridge.The actual file is:/etc/network/interfaces and the definition of the bridge is :

# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet manual
iface tap0 inet manual

# Our bridge initially contains just the ethernet interface and is configured to use DHCP
auto br0
  iface br0 inet dhcp
  bridge_ports eth0

# You can delete these lines if you do not whish to use Wi-fi 
allow-hotplug wlan0
iface wlan0 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

allow-hotplug wlan1
iface wlan1 inet manual
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

This setup uses DHCP for the bridge. Setting up a static IP is explained in the Network Configuration section of the Debian Wiki. The same pages provide more information and details about bridging. The actual link is here.

At this point a server reboot is required in order to verify the bridge setup. When the server is up again you can check that the bridge is working by examining the outcome of the ip addr command which should be similar to this:

pi@gabriella:/etc/openvpn $ ip addr
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000
    link/ether b8:27:eb:b2:d8:f2 brd ff:ff:ff:ff:ff:ff
    inet 169.254.30.59/16 brd 169.254.255.255 scope global eth0
       valid_lft forever preferred_lft forever
3: br0:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether b8:27:eb:b2:d8:f2 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.240/24 brd 10.0.1.255 scope global br0
       valid_lft forever preferred_lft forever
    inet 10.0.1.205/24 brd 10.0.1.255 scope global secondary br0
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:ebff:feb2:d8f2/64 scope link 
       valid_lft forever preferred_lft forever

install openvpn

With the bridge working the next step will be installation and configuration of the OpenVPN server itself. Before we proceed with the server installation we will lay out the necessary fact about the network the server is on:

  • Our network is a class C net with a broadcast address of 10.0.1.0/24
  • Default gateway is 10.0.1.1
  • Network DNS is 10.0.1.152
  • The target network uses DHCP. We have set aside the range between 10.0.1.32 and 10.0.1.39 to be used by our clients,

Having clear our theses fact we may begin our installation.

pi@gabriella:~ $ sudo apt-get install openvpn easy-rsa 

Since all the commands that we will type from now on will require root privileges, it is wise to do a :

pi@gabriella:~ $ sudo su -
root@gabriella:~# cd /etc/openvpn/
root@gabriella:/etc/openvpn#

We will create a new server configuration file. This file is /etc/openvpn/server.conf with the following contents

# --------------------------------------------------------------------------------
# OpenVPN bridging configuration file.
# Adopted from the Ubuntu Community Page at https://help.ubuntu.com/community/OpenVPN
# Date may -15th 2016
# --------------------------------------------------------------------------------
mode server
tls-server

local 10.10.1.240       ## ip/hostname of server
port 1194               ## default openvpn port
proto udp

# --------------------------------------------------------------------------------
# Bidging directive
# --------------------------------------------------------------------------------
dev tap0 

script-security 2       ## allow calling up.sh and down.sh
up "/etc/openvpn/up.sh br0 tap0 1500"
down "/etc/openvpn/down.sh br0 tap0"

persist-key
persist-tun

# --------------------------------------------------------------------------------
# certificates and encryption
# --------------------------------------------------------------------------------
ca ca.crt
cert server.crt
key server.key          # This file should be kept secret
dh dh2048.pem
tls-auth ta.key 0       # This file is secret

cipher BF-CBC           # Blowfish (default)
comp-lzo

# Allow multiple clients to connect using the same client keys
# duplicate-cn

# --------------------------------------------------------------------------------
# DHCP Information
# --------------------------------------------------------------------------------
ifconfig-pool-persist ipp.txt
# The first address is the bridge address of the server the second is the netmask to use
# and the next twoo addresses are the range that should be assigned to clients
server-bridge 10.0.1.240 255.255.255.0 10.0.1.32 10.0.1.39
push "dhcp-option DNS 10.0.1.152"
push "dhcp-option DOMAIN simsons"
max-clients 8           ## set this to the max number of clients that should be connected at a time

# --------------------------------------------------------------------------------
# log and security
# --------------------------------------------------------------------------------
user nobody
group nogroup
keepalive 10 120
status openvpn-status.log
verb 3

Next we will need to create the two scripts that hook and unhook our tap device to the server bridge. These files should be called up.sh and down.sh (These are the names in server.conf file) with the following contents.

#!/bin/sh
# File up.sh adds a device to a bridge with a specified MTU

BR=$1    # bridge to add device to
DEV=$2   # actual device to add
MTU=$3   # MTU value

/sbin/ip link set "$DEV" up promisc on mtu "$MTU"
/sbin/brctl addif $BR $DEV
and
#!/bin/sh
# file down.sh remove a device from a bridge

BR=$1
DEV=$2

/sbin/brctl delif $BR $DEV
/sbin/ip link set "$DEV" down

Do not forget, to make both scripts executable

root@gabriella:/etc/openvpn# chmod +x up.sh down.sh 

Having done all that, it's time for a break. We will create our own DH 2048 bit file.

root@gabriella:/etc/openvpn# openssl dhparam -out dh2048.pem 2048
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
................+........................................................................................................+.........................................

Even on a four core Raspberry-PI2 model B board, this takes well over 40 minutes, so sit back and relax

Create the Certificates

With the dh2048.pem file in place, we will start creating our server and client certificates by first copying the easy-rsa scripts to our servers setup directory and next creating the folder that will host our keys.

In order to make things a bit more secure we will create an additional tls-auth directive and the related key

root@gabriella:/etc/openvpn# openvpn --genkey --secret ta.key
root@gabriella:/etc/openvpn# cp -r /usr/share/easy-rsa/ /etc/openvpn
root@gabriella:/etc/openvpn# cd easy-rsa/
root@gabriella:/etc/openvpn/easy-rsa# mkdir keys

The Easy-RSA package that comes with the latest version of Rasbian (June-2019) provides three openssl.conf files depending on the installed version of the openssl package. Raspberry pi uses openssl 1.0 so, we need to link the correct version configuation file to openssl.conf.

# ln -sf openssl-1.0.0.cnf openssl.cnf

Next step is the creation of the actual server certificates. Open file /etc/openvpn/easy-rsa/vars and fill in the details accordingly.

root@gabriella:/etc/openvpn# vim /etc/openvpn/easy-rsa/vars 

Change the lines (first one is line 64 in my version) that refer to the certificate creation parameters, so they look similar to this:

# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY="gr"
export KEY_PROVINCE="Rodope"
export KEY_CITY="Komotini"
export KEY_ORG="Aryballos"
export KEY_EMAIL="admin@aryballos.gr"
export KEY_OU="Aryballos-IT-Services"

# X509 Subject Field
export KEY_NAME="server"
# Add this for Debian Stretch. ./build-ca will not work otherwise
export KEY_ALTNAMES="server"

Save, exist, run the file ... and do a clean-all to start fresh.

root@gabriella:/etc/openvpn/easy-rsa# . ./vars 
NOTE: If you run ./clean-all, I will be doing a rm -rf on /etc/openvpn/easy-rsa/keys
root@gabriella:/etc/openvpn/easy-rsa# ./clean-all

The next command will build the required certificate authorities for the server (Hit ENTER when there is a prompt).

root@gabriella:/etc/openvpn/easy-rsa# ./build-ca
Generating a 2048 bit RSA private key
...........................................................................................................+++
..............................................+++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [gr]:
State or Province Name (full name) [Rodope]:
Locality Name (eg, city) [Komotini]:
Organization Name (eg, company) [Aryballos]:
Organizational Unit Name (eg, section) [Aryballos-IT-Services]:
Common Name (eg, your name or your server's hostname) [Aryballos CA]:
Name [server]:
Email Address [admin@aryballos.gr]:
root@gabriella:/etc/openvpn/easy-rsa# 

Now it's time to build the actual server key.

root@gabriella:/etc/openvpn/easy-rsa# ./build-key-server server
Generating a 2048 bit RSA private key
.................................................................................................................................+++
....................................................+++
writing new private key to 'server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [gr]:
State or Province Name (full name) [Rodope]:
Locality Name (eg, city) [Komotini]:
Organization Name (eg, company) [Aryballos]:
Organizational Unit Name (eg, section) [Aryballos-IT-Services]:
Common Name (eg, your name or your server's hostname) [server]:
Name [server]:
Email Address [admin@aryballos.gr]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/openvpn/easy-rsa/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'gr'
stateOrProvinceName   :PRINTABLE:'Rodope'
localityName          :PRINTABLE:'Komotini'
organizationName      :PRINTABLE:'Aryballos'
organizationalUnitName:PRINTABLE:'Aryballos-IT-Services'
commonName            :PRINTABLE:'server'
name                  :PRINTABLE:'server'
emailAddress          :IA5STRING:'admin@aryballos.gr'
Certificate is to be certified until May 13 14:09:17 2026 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
root@gabriella:/etc/openvpn/easy-rsa# 

Copy the certificates to their designated place.

root@gabriella:/etc/openvpn/easy-rsa# cp /etc/openvpn/easy-rsa/keys/{server.crt,server.key,ca.crt} /etc/openvpn

Yes we are ready fire up the openvpn server!

root@gabriella:/etc/openvpn/easy-rsa# service openvpn start
root@gabriella:/etc/openvpn/easy-rsa# service openvpn status
● openvpn.service - OpenVPN service
   Loaded: loaded (/lib/systemd/system/openvpn.service; enabled)
   Active: active (exited) since Sun 2016-05-15 17:13:53 EEST; 4s ago
  Process: 2009 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
 Main PID: 2009 (code=exited, status=0/SUCCESS)

May 15 17:13:53 gabriella systemd[1]: Started OpenVPN service

At this point it would be very wise to switch to your ISP's router or firewall setup page and enable port 1194 forwarding between the external IP address of your router and the internal IP address of the OpenVPN server.

The final step will be to generate keys for the client. OpenVPN will not allow two clients with the same key to log on simultaneously, unless you add a line with duplicate-cn in the server.conf parameter file. Client certificates are build the same way as the server's, only this time you get to use the build-key script

root@gabriella:/etc/openvpn/easy-rsa# ./build-key client
Generating a 2048 bit RSA private key
..................+++
................+++
writing new private key to 'client.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [gr]:
State or Province Name (full name) [Rodope]:
Locality Name (eg, city) [Komotini]:
Organization Name (eg, company) [Aryballos]:
Organizational Unit Name (eg, section) [Aryballos-IT-Services]:
Common Name (eg, your name or your server's hostname) [client]:
Name [server]:
Email Address [admin@aryballos.gr]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/openvpn/easy-rsa/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'gr'
stateOrProvinceName   :PRINTABLE:'Rodope'
localityName          :PRINTABLE:'Komotini'
organizationName      :PRINTABLE:'Aryballos'
organizationalUnitName:PRINTABLE:'Aryballos-IT-Services'
commonName            :PRINTABLE:'client'
name                  :PRINTABLE:'server'
emailAddress          :IA5STRING:'admin@aryballos.gr'
Certificate is to be certified until May 13 14:31:07 2026 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
root@gabriella:/etc/openvpn/easy-rsa# 

You may create a different key for each of the clients you want to allow access. Otherwise enable the duplicate-cn option on your server configuration file to allow multiple clients to connect with the same key.

Client setup

Each client must have the openvpn package installed. After installation move to the /etc/openvpn folder create a file named client.conf and enter the following:

### Client configuration file for OpenVPN

# Specify that this is a client
client

# Same setting as on server
script-security 3

# Bridge device setting
dev tap
proto udp

# Host name and port for the server (default port is 1194)
# note: replace with the correct values your server set up
remote  extennal_ip.of.openvpn.server 1194

# Client does not need to bind to a specific local port
nobind

user nobody
group nogroup

# Keep trying to resolve the host name of OpenVPN server.
## The windows GUI seems to dislike the following rule. 
##You may need to comment it out.
resolv-retry infinite

# Preserve state across restarts
persist-key
persist-tun
mute-replay-warnings

# SSL/TLS parameters - files created previously
ca /etc/openvpn/ca.crt
cert /etc/openvpn/client.crt
key /etc/openvpn/client.key
ns-cert-type server

# Since we specified the tls-auth for server, we need it for the client
# note: 0 = server, 1 = client
tls-auth /etc/openvpn/diaamath/ta.key 1

# Specify same cipher as server
cipher BF-CBC

# Use compression
comp-lzo

# Log verbosity (to help if there are problems)
verb 3

up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

Next, copy the files ta.key, ca.crt, client.crt and client.key from the the server to the clients /etc/openvpn. directory.

Disable autostart of the OpenVPN service.

sudo update-rc.d openvpn disable

Reboot the client. (The OpenVPn setup usually fires up the OpenVPN service) And finally connect

sudo openvpn /etc/openvpn.client.conf

That should do it!

Links

This howto has been assembled using various sources. Most important being:

  1. The Ubuntu Community OpenVPN Wiki
  2. The Digital Ocean Tutorail about setting up an Open VPN Server on Debian 9
  3. The OpenVPN howto on the Debian Wiki

Friday, 26 February 2016

Java Swing GUI's default and cancel buttons

None of these are mine. I just copied and re-factored them from here and here in stackoverflow.com.

The code comes from a login form that needs to have it's login button clicked when enter is pressed and to be closed when user hits escape.

Other frameworks like good old VCL and WindowsForms allow this to be done by visually managing properties, but with Java you have to type something like this :

        // set default botton on ENTER
        this.getRootPane().setDefaultButton(jButtonLogin);

        // set escape to close this dialog
        KeyStroke escapeKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);        
        this.getRootPane().registerKeyboardAction( e -> this.dispose(), escapeKeyPressed, JComponent.WHEN_IN_FOCUSED_WINDOW);

Enjoy.

Saturday, 13 June 2015

JPA Queries containing count

A simple howto and reference regarding the usage of the count() function in your JPA code.

First thing is correct syntax. Counting the number of rows is not done using the syntax count(*) but rather count(entity). So a proper named query declaration would be something like :

@NamedQueries({
    @NamedQuery(
            name = "PixelStation.pixelStationExists",
            query = "SELECT COUNT(p) FROM PixelStation p WHERE p.pixel = :pixel AND p.station = :station"
    )
})

Next thing to remember is that the class returned by the query is the Java Long. So getting a value would be like:

        Long count = _entityManager.createNamedQuery("PixelStation.pixelStationExists", Long.class)
                .setParameter("station", station)
                .setParameter("pixel", pixel)
                .getSingleResult();

        // record exists no need to do anything
        if (count >= 1)
            return;

        // insert new record
        ...

Friday, 10 April 2015

IP tables forward traffic between ethernet and wi-fi

Recently, I was asked to create a Linux based WI-fi access point using the new Raspberry Pi 2 Model B. This project had a .. happy ending, thanks to the numerous bloggers of the π community. Here, there and there just to mention a few.

What I wish to keep as a reference to this blog post is the iptables setup that allowed the device to forward IP v4 traffic between the Ethernet and the Wi-fi ports.

To get started create a file like /etc/iptables.ip-v4.nat containing the following:

# Generated by iptables-save v1.4.14 on Mon Mar 23 18:48:53 2015
*filter
:INPUT ACCEPT [121:10892]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [5:800]
-A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wlan0 -o eth0 -j ACCEPT
COMMIT
# Completed on Mon Mar 23 18:48:53 2015
# Generated by iptables-save v1.4.14 on Mon Mar 23 18:48:53 2015
*nat
:PREROUTING ACCEPT [96:7931]
:INPUT ACCEPT [20:2899]
:OUTPUT ACCEPT [2:224]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o eth0 -j MASQUERADE
COMMIT
# Completed on Mon Mar 23 18:48:53 2015

Next, edit /etc/network/interfaces and place the following after the wi-fi setup at the very end:

# Configure firewall to allow traffic between wlan0 and eth0
up iptables-restore < /etc/iptables.ip-v4.nat

Wednesday, 18 March 2015

MySQL Cross database foregin keys

Here is a small query to display all foreign keys across different databases. May come in very handy when deciding which database to restore first :)

USE information_schema;

SELECT * 
    FROM 
        KEY_COLUMN_USAGE 
    WHERE 
        CONSTRAINT_SCHEMA != REFERENCED_TABLE_SCHEMA;

Thursday, 12 March 2015

Last modified date/time for CakePHP projects

What is the last modification date of a CakePHP project? To answer that you would probably have to ask what is the latest date and time that any file was modified in your CakePHP project sub-folders. These sub-folders are usually Model, View, Controller, webroot and perhaps Vendor or Console.

In order to solve this in Linux, I crafted the following bash script:

#!/bin/bash

BASE_PATH="/var/www/html/MyProject/app"           # replace with your own
SUB_COMPONENTS="Model View Controller webroot"    # add folders as needed

LAST_MODIFIED=$(
 for COMPONENT in $SUB_COMPONENTS 
 do
  SUB_PATH=$BASE_PATH/$COMPONENT
  RESULT=`find $SUB_PATH -type f -exec stat --format '%z' "{}" \; | sort -r | head --bytes=16`
  echo $RESULT
 done | sort -r | head --lines=1 )

echo $LAST_MODIFIED
exit 0

the idea is to get all files in each of the paths, contained in the $SUB_COMPONENTS variable, using the find command. Then execute stat to retrieve the last modification datetime, sort the results in reverse order and finally use head to retrieve the first 16 characters which make up the first YYYY-mm-dd HH:ii characters of the timestamp.

The entire result of the for loop is then fed to sort once more to create the list with the highest time stamp being first. Finally we use head again to throw away all output lines apart from the first.

An example of using this in CakePHP controller code would be something like:

    const LAST_MODIFIED_COMMAND = '/opt/bin/cakeLastModified';

    ...

    public function about()
    {
        $this->set('lastModified', exec(self::LAST_MODIFIED_COMMAND));
    }

... and then display the value of the $lastModified variable in the corresponding about view.

Note: Once again, I would like to give credit to the good people at stackoverflow.com for providing answers to all the minor problems that made this one up. So this code would not be here if l0b0 had not provided such a concise and clear answer to Sorting in shell script and if How to recursively find and list the latest modified files in a directory with subdirectories and times? did not have a working answer.

Saturday, 14 February 2015

Java: Read String from console

Once again, I was out there trying to find the neatest solution for reading a string from the IDE console. It turns out that the shortest piece of code that one can write to achieve this would be :

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

...

     public static String getString() throws IOException
     {
        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {;
            return br.readLine();
        }
    }

Wednesday, 15 October 2014

Listbox mnipulation with jQuery

This is my easy to paste reference code for list-box manipulation using jQuery. By the way, the HTML <input "type"="select"> element, will create what desktop programmers usually refer as a combo-box. To make the input display as a list box, we need to specify an additional size="N" attribute where N refers to the number of visible items of the list.

So, suppose that we have a select input somewhere in an HTML page and that we need to add a button that removes the selected item from the input's options list.

       // remove the selected item from the list box
       jQuery('#deleteButton').click(function(){
            jQuery("#myListBox option:selected").remove();
            return false;
        });

By the same token, we can also create an other button that empties the entire options list

        // remove all items from list box
        jQuery('#deleteAllButton').click(function(){
            // check that there is something to remove
            if (jQuery("#myListBox option").length == 0)
                return false;

            // verify that user really wants to do this
            if (!confirm(''))
                return false;

            // empty list box
            jQuery("#myListBox option").remove();
            return false;
        });
    });

Finally, to add a new item at the end of the options box we can use a code fragment that looks more or less like this:

                    var newOptionhtml ='<option value="'
                        + response.id
                        + '">'
                        + response.name
                        + ' </option>';

                    jQuery("#myListBox").append(newOptionhtml);

Needles to say that all the above have been collected from various Stack Overflow questions and answers.

Saturday, 13 September 2014

GNOME3: How to enable desktop icons and right click menu

This is the third time I am looking this up, so I am making a quick howto note here.

So in order to enable desktop icons on a newly installed gnome3 desktop perform the following steps:

  1. Open the dconf-editor program.
  2. Locate the page following path org → gnome → desktop → background
  3. Check the Show desktop icons option.

Monday, 14 July 2014

CakePHP Find out the link that brough us to the current page

Most web applications today have some kind of menu build with anchor tags. The problem that the following script -- courtesy of my friend Anestis from alfasoftware.gr -- solves, is how to determine the actual link that was used to bring the user to the currently displayed page.

To use it, place it inside a script tag towards the end of your app/Views/Layout/default.ctp file (just before the closing body tag, will do just fine) and a little bit of CSS code in your appropriate style file (again app/webroot/css/cake.generic.css is a good candidate).

The CSS code is pretty easy :

a.active {
    background-color: yellow; // add anything you like
}

and the javascript :


        <script type="text/javascript">
            // add the "active" class to the navigation link that brought us to this page
            jQuery( function() {
                // retrieve the relative url of the current page
                var curUrl = "<?php echo (Router::url( NULL, FALSE)); ?>";
                // in a cake application a relative URL is usually like
                // /application/controller/action/param1/param2 ...
                // so what we really need is the first three pieses of the URL
                var tokens = curUrl.split("/").slice(0,4);
                curUrl = tokens.join("/");
                // if there is any pagination information then the word "index" also appears in the URL
                // in this case we need to remove it, so it can match generated URL
                var indexIndex = curUrl.indexOf('index');
                if ( indexIndex > -1)
                    curUrl = curUrl.substring( 0, indexIndex - 1);

                // for each page anchor tag
                $('a').each( function() {
                    // retrieve the arnchor's target
                    var ref = $(this).attr("href");
                    // so if that anchor points to the current page
                    if(ref === curUrl){
                        $(this).addClass("active");
                    }

                });
            });
        </script>

Enjoy!

Sunday, 18 May 2014

How to remove a particular host key from SSH's ./ssh/known_hosts file

I will leave the sed solution for the real gurus. As far as I am concerned the easy way to get the job down is use the ssh-keygen -R your_host command.

If you are working in a environment with a DNS suffix, then you will probably need a second invocation like: ssh-keygen -R your_host.your_domain.

Friday, 4 April 2014

Setting up Environment variables before Apache starts

That was the third time I had to look this up, so I am putting it down for reference.

On Red Hat machines, apachectl sources /etc/sysconfig/httpd, so any variables you set there will be available to the apache runtime environment. Debian based systems use /etc/apache2/envvars for the same purpose.

Thursday, 3 April 2014

Linux (EL6) Required packages for installing the 64 bit Oracle 12c Client

The Oracle documentation has a list of the packages required in order to install the database client software for Enterprise Linux 6.

Since the minimum versions requirements are satisfied on an updated EL6 system, all one has to do is just copy and paste the names into a single yum command in order to complete the step. Did it once this morning and I hope that if I ever have to repeat it, I will just copy and paste the following:

yum -y install binutils compat-libcap1 compat-libstdc++-33.i686 compat-libstdc++-33.x86_64 \
gcc gcc-c++ glibc.i686 glibc.x86_64 glibc-devel.x86_64 glibc-devel.i686 \
ksh libgcc.i686 libgcc.x86_64 \
libstdc++.x86_64 libstdc++.i686 libstdc++-devel.x86_64 libstdc++-devel.i686 \
libaio.x86_64 libaio.i686 libaio-devel.x86_64 libaio-devel.i686 \
libXext.x86_64 libXext.i686 libXtst.x86_64 libXtst.i686 \
libX11.x86_64 libX11.i686 \
libXau.x86_64 libXau.i686 \
libxcb.x86_64 libxcb.i686 \
libXi.x86_64 libXi.i686 \
make sysstat

PS: If not running this as root, remember to prefix this with sudo :)

Thursday, 20 March 2014

CakePHP-2 and AJAX The dependent list boxes problem (remake)

Forward

Back in 2010, I had written a post regarding the case of dependent list boxes in a CakePHP view. Back at those days CakePHP was at version 1.2 and support for Javascript and AJAX was very limited. Today I shall revise this using JQuery and JSON encoding which will make things simpler and easier to understand, implement and maintain.

The long story short

Suppose you have a page with two list boxes. One contains a standard set of values while the second one's list of values must be dynamically updated depending on the actual selected value of the first.

In our (sort of) real life example we have a list of commissions (aka production orders) that produce a series of products of varying lengths. The list of lengths that each commission is allowed to produce is available via a detail table and our goal is write an addProduct action and view that allows the user to specify the commission based on which the actual product was produced and the actual length of the product that should be one of the assigned commission lengths. The Product model has a commission_id and an actual_length fields. So each time the commission combo box changes the actual length field input options should also change in order to contain the commissions list of allowed lengths.

Getting Started

To begin with our tutorial make sure that your standard layout references the jQuery library. The easiest was to do this would be to open APP/View/Layout/default.ctp and make sure that a line like

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>

can be found somewhere in your html's head section.

The next thing that needs to be done is to add the RequestHandler component in our AppController. Add or modify your existing source so it looks more or less like this.

class AppController extends Controller {
    public $components = array(
        'RequestHandler', 
        ...
    );

    ,,,
}

Next we need to inform our routing system that it should also parse json URLs. So the line

Router::parseExtensions('json');

should be added to the APP/Config/routes.php file right below the other Router::xxx() commands.

Create the AJAX method and view to return the JSON encoded list of lengths

The next thing to do is create the action that will return the list of lengths to be sent back to the view given commission id. The best place to put it will be the commissions controller. The code for the function looks a lot like the one baked by view. We just need to make sure that the data returned "contain" the correct detail information

    public function getRequestedLengths($id)
    {
        if (!$this->Commission->exists($id)) 
            throw new NotFoundException(__('Invalid record'));
        
        $options = array(
            'conditions' => array(
                'Commission.' . $this->Commission->primaryKey => $id
            ),
            'contain' => array(
                'CommissionProduct',
            )
        );
        $this->set('commission', $this->Commission->find('first', $options));
    }

The view for the method should be placed in: APP/View/Commissions/json/get_requested_lengths.ctp.

<?php
/*
 * Create and echo a json encoded list of the allowed lengths
 ^/
$output = array();
if (!empty($commission['CommissionProduct']))
    foreach ($commission['CommissionProduct'] as $commissionProduct)
        $output[] = $commissionProduct['actual_length'];


echo json_encode($output);

So now if we point our browser towards http://yourserver/projectPath/Commissions/getRequestedLengths/7.json, we will receive a response with a JSON array containing all allowed lengths for commission id 7. The actual response will be something like ["45900","23400"].

Building the addProduct view

So far we have the mechanism to retrieve the required data. The final step will be to use it in the actual add product view, the PHP part of which should look more or less like this:

<div class="products form">
    <?php echo $this->Form->create('Product'); ?>
        <fieldset>
            <legend>Add Product</legend>
            <?php echo $this->Form->input('commission_id', array('empty' => __('Please select a commission'))); ?>
            <?php echo $this->Form->input('operator_id'); ?>
            <?php echo $this->Form->input('shift'); ?>
            <?php
                echo $this->Form->input(
                'status',
                array(
                    'type' => 'select',
                    'options' => $statusList
                )
                );
            ?>
            <?php echo $this->Form->input('actual_length', array('type' => 'select')); ?>
            <?php echo $this->Form->input('gross_weight'); ?>
        </fieldset>
    <?php echo $this->Form->end('Save'); ?>
</div>

The final part will be the adding of Javascript code to make our form responsive.

<script type="text/javascript">
    var commissionsCombo;
    var allowedLengthsCombo;

    jQuery(function() {
        commissionsCombo = jQuery('#ProductCommissionId');
        allowedLengthsCombo = jQuery('#ProductActualLength');

        commissionsCombo.change( function() {
            var selectedCommission = this.value;  // or $(this).val()
            // build the url that contained the selected commission code
            var ajaxUrl =
                    '<?php echo Router::url(array('controller' => 'Commissions', 'action' => 'getRequestedLengths', 'admin' => FALSE), TRUE)?>'
                    + '/'
                    + selectedCommission
                    + '.json';

            // do a "synchronous" AJAX call
            jQuery.ajax({
                    type:'GET',
                    async: false,
                    cache: false,
                    url: ajaxUrl,
                    success: function(response) {
                        // remove all options from the allowed metres per bobbin
                        allowedLengthsCombo.find('option').remove();

                        // add all returned values
                        for (var i = 0; i < response.length; i++) {
                            var currentKey = response[i];
                            var currentKeyDescr = response[i] + ' metres';
                            var optionText = '<option value="'
                                    + currentKey
                                    + '">'
                                    + currentKeyDescr
                                    + '</option>';
                            allowedLengthsCombo.append(optionText);
                        }
                    }
            });
        });
    });
</script>

As a last statement The code for manipulating the select input options comes from the very consise post from StackOverflow.com