Apache and forwarding a client certificate Id to WebSocket

Recently I came across a problem of forwarding a certificate Id to backend service for the authentication purposes. I also do not want to handle SSL at services.

Let’s say I have a server setup as follows: There is an Angular website on port 4200 and REST/Websocket services on port 3000. REST services are accessible over endpoint /kumuluz and Websocket connections via /v1/devices. As a common facade to access these services I set up Apache as a reverse proxy as in an example configuration below.

To extract a field from a client certificate (e.g. CN in my case) and forward request to a backend REST server with an additional header field is not a problem. I just extract property %{SSL_CLIENT_S_DN_CN}s and set a header field clientId.

The problem comes, when you would like to do the same for the Websocket connections – you cannot set header for these type of connections. But you can do a workaround (the point of this post): Tell clients to connect to the endpoint /v1/devices/CLIENT_ID and then check if the parameter matches the client id of underlying client certificate. Now you forced the client to use the correct ids in URL, which you can use for authentication as Apache forwards only requests where SSLRequire successes.


<VirtualHost *:80>
   ServerName portal.zitnik.si
   Redirect permanent / https://portal.zitnik.si/
</VirtualHost>

<VirtualHost *:443>
        ServerAdmin slavko@zitnik.si
        ServerName portal.zitnik.si
        ServerAlias portal.zitnik.si

        DocumentRoot /var/www

        ProxyPreserveHost On
        ProxyRequests Off

        ProxyPass /images !
        
        ProxyPass /v1/devices ws://localhost:3000/v1/devices
        ProxyPassReverse /v1/devices ws://localhost:3000/v1/devices

        ProxyPass /kumuluz http://localhost:3000
        ProxyPassReverse /kumuluz http://localhost:3000

        ProxyPass / http://localhost:4200/
        ProxyPassReverse / http://localhost:4200/

        RedirectMatch ^/$ https://portal.zitnik.si

        SSLEngine on
        SSLCertificateFile /home/slavkoz/certs/portal.zitnik.si.crt
        SSLCertificateKeyFile /home/slavkoz/certs/portal.zitnik.si.key

        SSLCACertificateFile /home/slavkoz/certs/CA.pem
        SSLVerifyClient none
        RequestHeader set clientId ""

        <Location /kumuluz/software>
                SSLVerifyClient require
                SSLVerifyDepth 1

                RequestHeader set clientId "%{SSL_CLIENT_S_DN_CN}s"
        </Location>

        <Location /v1/devices>
                SSLVerifyClient require
                SSLVerifyDepth 1

                SetEnvIf Request_URI "/v1/devices/(.*)$" CLIENT_ID=$1
                SSLRequire       %{SSL_CLIENT_S_DN_CN}  eq %{ENV:CLIENT_ID}
        </Location>
</VirtualHost>

Creating a Mac OS .app from a runnable JAR file

Here we solve a problem that many developers face when bundling java applications into an .app. We are going to correctly set the current working path for your Java Application.

Mac OS applications (.app files) are basically packages with a specific folder structure. You can easily explore each app’s structure by clicking on it using right click in Finder and selecting “Show Package Contents”.

Screen Shot 2016-02-21 at 11.42.41

Screen Shot 2016-02-21 at 11.42.53

 

Creating a custom .app

Create a folder PROGRAM_NAME.app. The Finder will ask you the following, which you will answer as add.

Screen Shot 2016-02-21 at 11.46.37

Now, show contents of you app and inside it create a folder structure /Contents/MacOS. Also create a blank script file launcher.sh (in my case, I am using Sociogram as a program name).

Screen Shot 2016-02-21 at 12.49.45
This script needs to be an executable, so open Terminal and run a command like this:

chmod a+x Sociogram.app/Contents/MacOS/launcher.sh

Maybe you have noticed that your .app does not have an icon. Therefore you need an .icns icon. I used a web service (https://iconverticons.com/online/) to convert my PNG file to an appropriate ICNS file.

Now, create a folder Resources and copy your icon there:

Screen Shot 2016-02-21 at 12.51.25

 

The last step now is to create a config file Info.plist that will define, which is an executable file in your app and where is your .app icon:

Screen Shot 2016-02-21 at 12.54.14

After these steps, you should have prepared an .app file, which looks like as follows:

Screen Shot 2016-02-21 at 12.55.39

Creating a runnable script for a JAR

First, let use create a Java Application that will print out the current working directory and package it into a runnable JAR (sociogram.jar):

import javax.swing.*;
import java.awt.*;
 
/**
 * Created by slavkoz on 21/02/16.
 */
public class Runner {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
 
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(new JTextField(System.getProperty("user.dir")), BorderLayout.CENTER);
        frame.setContentPane(panel);
 
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

If we now just run that jar from a launcher script, the default working directory for Java would be “/”, so we may have problem accessing resources, that are packaged inside our .app.

Therefore, let us create an executable socioRunner script that will accept current working dir and run our java application from there. We put the script in the same directory as the launcher script.

#!/bin/sh
 
DIR=$1
APP_JAR="sociogram.jar"
APP_NAME="Sociogram 5.0"
 
cd "$DIR"
java -Xdock:name="$APP_NAME" -Xdock:icon="$DIR/../Resources/application.icns" -cp "$DIR;.;" -jar "$DIR/$APP_JAR"

Now, we can update the launcher script, which will detect the directory, where it resides and run the socioRunner script with a parameter:

#!/bin/sh
 
# Set the working directory
DIR=$(cd "$(dirname "$0")"; pwd)
 
# Run the application
exec "$DIR/socioRunner" $DIR

So, voila, now we get the following result when the .app application is run from Finder:

Screen Shot 2016-02-21 at 13.32.45

You can download the whole .app file from here: http://zitnik.si/wordpress/manual_upload/Sociogram.app.zip

A simple custom solution to multi-language support using JS

Recently, I needed to add a multi-language support to a website that was run using PHP. Sure, I could use some i18n PHP framework to deliver translated web-page directly from a server, but I decided to design a simple approach based on Javascript.

Here it goes …

The default language is supposed to be slovene, so visiting a page by url http://mywebpage would show a slovene version. To get a webpage in a specific language, you need to explicitly define the language using a parameter, like so: http://mywebpage?lang={sl, hr, en}. Of course, this is used in a header of a web page for a languages selection menu:

<a id="lang-sl" href="/?lang=sl">Slovenski</a>|
<a id="lang-hr" href="/?lang=hr">Hrvatski</a>|
<a id="lang-en" href="/?lang=en">English</a>

In the webpage, I introduced a “lang” HTML tag, which acts as a placeholder for a language-specific text:

<lang id="home" />

For each language I create a separate JS file that includes a map variable, whose keys are ids used in HTML placeholders and values are translated texts. For example, a file “lang.sl.js” includes slovene translations:

var lang = {
    home: "Domov",
    about: "O programu",
    functionalities: "Funkcionalnosti",
    ....
};

Now, as we have everything prepared, we are going to write a JS script that (A) automatically detects a selected language from query string, (B)  includes an appropriate translation file and (C) automatically populates prepared HTML placeholders. I do this as follows:

$(document).ready(function() {
 
	$.urlParam = function(name){
		var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
		if (results==null){
		   return null;
		}
		else{
		   return results[1] || 0;
		}
	}
 
	function loadJS(file) {
		var jsElm = document.createElement("script");
		jsElm.type = "application/javascript";
		jsElm.src = file;
 
		$("body").prepend(jsElm);
	}
 
	if ($.urlParam("lang") == "en") {
		loadJS("js/lang.en.js");
		$("#lang-en").css("font-weight", "bolder");
	} else if ($.urlParam("lang") == "hr") {
		loadJS("js/lang.hr.js");
		$("#lang-hr").css("font-weight", "bolder");
	} else {
		loadJS("js/lang.sl.js");
		$("#lang-sl").css("font-weight", "bolder");	
	}
 
	function fillIn(key, value) {
		document.getElementById(key).innerHTML = value;	 	
	}
 
 
	//Fill in translations	
	for(var key in lang) {
	  fillIn(key, lang[key]);
	}
 
});

Additionally to that basic example I added some exceptions to insert language-specific values into some HTML tag attributes.

Such approach works like a charm for about 200 language keys – I have not tested for more. The whole site is served by an RPi and JS loading of language-specific texts is not noticeable on a client.

Part 3/3: Reading analog input using RPi

Continuing from the previous example, we would like our LED to turn on automatically, based on the light level of the environment.

Photoresistor

First we need to read the value of the photocell that measures the value of light. Photocells (aka. photoresistor) acts as a dynamically-adapting resistor according to the light levels. In dark areas, the resistance is high and in bright areas the resistance is low.

As Raspberry Pi does not have an analog input, we can make a trick to read a value from an analog sensor (resistor-based sensor). We just use a small capacitor and measure time that is needed to fill the capacitor to the full level.

On Raspberry Pi we use 3.3V pin as power supply, GND as ground and pin 18 as an input pin that will be used to measure time to fill the capacitor. In the circuit we measure voltage levels using pin 18 between photoresistor and capacitor.

To get the light level, we need to:

  1. Set pin 18 as out and to LOW voltage.
  2. Set pin 18 as input to be able to read input voltage. Now we can just read if voltage is LOW or HIGH.
  3. Measure, how much time is needed until read voltage on pin 18 is HIGH.

Normally you can use a 1μF but we had just a capacitor of 100μF (if it is designed to higher voltage, it is okay). The difference is only you will need more time to fill the capacitor in darker conditions. In our case, we need about 800000ms to detect dark light and about 30000ms to detect twilight.

Automatic light switching

Above we got the information whether the light conditions are daylight, twilight or darkness. Now we set a LED that will be turned off in daylight, burn lightly in twilight and be very bright in darkness.

For this, we use two pins to turn on a LED and for each pin, we use different resistor to set the brightness of a LED. For darkness we use a 220Ohm resistor and for twilight we use 1120Ohm (2x560Ohm) resistor.

The script to control all of the above looks like:

#!/usr/bin/env python
import RPi.GPIO as GPIO, time, os
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
 
#Variables setup
TWILIGHT_THRESHOLD = 30000
DARK_THRESHOLD = 800000
LIGHT_STATUS_PIN = 18
TWILIGHT_LIGHT_PIN = 22
DARKNESS_LIGHT_PIN = 23
 
class Light(object):
        DAYLIGHT = "Daylight"
        TWILIGHT = "Twilight"
        DARKNESS = "Darkness"
 
def LightInfo():
        GPIO.setup(LIGHT_STATUS_PIN, GPIO.OUT)
        GPIO.output(LIGHT_STATUS_PIN, GPIO.LOW)
        time.sleep(0.1)
        GPIO.setup(LIGHT_STATUS_PIN, GPIO.IN)
 
        # This takes about 1 millisecond per loop cycle
        repeats_to_full_capacitor = 0
        while (GPIO.input(LIGHT_STATUS_PIN) == GPIO.LOW):
                repeats_to_full_capacitor += 1
 
        if (repeats_to_full_capacitor < TWILIGHT_THRESHOLD):
                return Light.DAYLIGHT
        elif (repeats_to_full_capacitor < DARK_THRESHOLD):
                return Light.TWILIGHT
        else:
                return Light.DARKNESS
 
def TurnLEDOnOff(status):
        #Turn all off
        GPIO.setup(TWILIGHT_LIGHT_PIN, GPIO.OUT)
        GPIO.setup(DARKNESS_LIGHT_PIN, GPIO.OUT)
        GPIO.output(TWILIGHT_LIGHT_PIN, GPIO.LOW)
        GPIO.output(DARKNESS_LIGHT_PIN, GPIO.LOW)
        time.sleep(0.1)
        #Turn appropriate pin on
        if (status == Light.TWILIGHT):
                GPIO.setup(DARKNESS_LIGHT_PIN, GPIO.IN)
                GPIO.output(TWILIGHT_LIGHT_PIN, GPIO.HIGH)
        elif (status == Light.DARKNESS):
                GPIO.setup(TWILIGHT_LIGHT_PIN, GPIO.IN)
                GPIO.output(DARKNESS_LIGHT_PIN, GPIO.HIGH)
 
#Main program
status = Light.DAYLIGHT
while True:
        newStatus = LightInfo()
        print newStatus
        if (newStatus != status):
                TurnLEDOnOff(newStatus)
                status = newStatus

When we run the script as “sudo ./LightSwitch.py” in daylight conditions, the LED is off:

IMG_0164

In twilight, the LED is not that bright:

IMG_0165

Lastly in the darkness, the LED becomes very bright:

IMG_0166

Part 2/3: OpenHAB + RPi + LEDs + Camera

We are continuing with the example from the first part of the tutorial: http://www.zitnik.si/wordpress/2016/02/04/part-13-controlling-leds-using-raspberry-pi/.

In this part we are going to install OpenHAB platform on an RPi and remotely control LEDs.

OpenHAB (http://www.openhab.org/)  is a software that is intended to connect to many sensors or devices for home automation. It works as a smart devices gateway and includes tools to design a custom GUI to control these connected smart devices. A GUI can be accessed using a web browser or from a nice mobile application (iOS, Android).

OpenHab Installation

We first installed OpenHAB core and then Demo from the official site: http://www.openhab.org/getting-started/downloads.html. These are compressed packages which I unzip into /opt/openhab folder. Within the new directory, there’ll be a folder called configurations. Within this folder create a copy of the default configuration file openhab_default.cfg and name it openhab.cfg. This is where you’ll store all your settings for openHAB and any bindings you need.

To start the OpenHAB server, run /opt/openhab/start.sh.

OpenHAB configuration

To control our LEDs we will need to create three files.

Create a file configurations/items/default.items. This will be an inventory for definition of our sensors. The file should look like:

Switch RedLight				"Rdeca luc"
Switch GreenLight			"Zelena luc"
Switch YellowLight			"Rumena luc"

The next file should define the rules and actions for these sensors. So, create a file named configurations/rules/default.rules to look like:

import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.action.pushover.*
import org.openhab.action.pushover.internal.*
 
rule "RedLight changed"
when
 Item RedLight received command ON
then
 logInfo("RedLight", "Received red light command to turn on.")
 executeCommandLine("python /home/pi/red_on.py")
 pushover("Rdeca luc je bila prizgana.")
end
 
rule "RedLight changed"
when
 Item RedLight received command OFF
then
 logInfo("RedLight", "Received red light command to turn on.")
 executeCommandLine("python /home/pi/red_off.py")
end

As you can see I also configured the pushover service so that I am notified about the change via a push notification. It can also be observed that on some command received, a log message is created and a command line script is executed. These scripts look the same as in the first part of the tutorial, where we introduced how to turn LED on or off.

In the last file, named configuration/sitemaps/default.sitemap we will define the GUI for our application. Our file looks like this:

sitemap demo label="Raspberry demo"
{
 Frame label="Luci" {
   Switch item=GreenLight label="Zelena luc"
   Switch item=YellowLight label="Rumena luc"
   Switch item=RedLight label="Rdeca luc"
 }
 Frame label="Videokamere" {
   Text label="Raspberry kamera" icon="video" {
     Frame label="Raspberry kamera" {
       Video url="http://localhost:8081?action=stream" encoding="mjpeg"
     }
   }
   Text label="Raspberry kamera" icon="garden" {
     Frame label="Raspberry kamera (snapshot)" {
       Image url="http://localhost:8081?action=snapshot" refresh=5000
     }
   }
 }
}

For now you can skip the “Videokamere” part as it defines video stream and snapshot images of a camera that we will attach to the raspberry (below).

As you save the file and run the server, the GUI can be accessed via a web browser using URL http://RPi_IP:8080:

Screen Shot 2016-02-04 at 14.01.19

You can also use this URL in a mobile application and have a native interface – e.g. on your iPhone, which looks like this (for our sitemap definition):

IMG_0162

You should now be able to turn on or off your LEDs using OpenHAB platform. Try it out!

OpenHAB and Raspberry Pi Camera Module

Now we would also like to check our lights remotely via a camera. We will use mjpeg stream for video streaming.

We have an RPi Camera Module, which we attached to the RPi. After that we run “sudo raspi-config” command and enable the camera module.

First we need to install some dependencies:

sudo apt-get install libjpeg8-dev
sudo apt-get install imagemagick[prismatic_encoded class=%%language-bash%% data-lang=%%bash%%]DQpzdWRvIGFwdC1nZXQgaW5zdGFsbCBsaWJqcGVnNjItZGV2DQpzdWRvIGFwdC1nZXQgaW5zdGFsbCBjbWFrZQ==[/prismatic_encoded]
[prismatic_encoded class=%%language-bash%% data-lang=%%bash%%]c3VkbyBhcHQtZ2V0IGluc3RhbGwgbGlidjRsLWRldg0KI2NyZWF0ZSBhIHN5bWJvbGljIGxpbmsNCnN1ZG8gbG4gLXMgL3Vzci9pbmNsdWRlL2xpYnY0bDEtdmlkZW9kZXYuaCAvdXNyL2luY2x1ZGUvbGludXgvdmlkZW9kZXYuaA==[/prismatic_encoded]

Then we download mjpeg repository and build the library:

[prismatic_encoded class=%%language-bash%% data-lang=%%bash%%]PHNwYW4gY2xhc3M9ImMiPiMgWW91IGNhbiBhbHNvIGNob29zZSB0byBkb3dubG9hZCBzb21lIHN0YWJsZSB2ZXJzaW9uIGluc3RlYWQgb2YgY3VycmVudCBtYXN0ZXI8L3NwYW4+DQpnaXQgY2xvbmUgaHR0cHM6Ly9naXRodWIuY29tL2phY2tzb25saWFtL21qcGctc3RyZWFtZXIuZ2l0IC4NCnN1ZG8gbWFrZSBjbGVhbiBhbGwNCg==[/prismatic_encoded]

Now copy the directory of build files to /opt/mjpg-streamer and run mjpeg streamer using the following command (I am using parameter vf to vertically flip the image):

LD_LIBRARY_PATH=/opt/mjpg-streamer /opt/mjpg-streamer/mjpg_streamer -i "input_raspicam.so -fps 5 -q 50 -x 640 -y 480 -vf" -o "output_http.so -w /opt/mjpg-streamer/www -p 8081" &

If everything is okay, a video stream should be accessible at http://RPi_IP:8081:

Screen Shot 2016-02-04 at 14.26.03

Also if OpenHAB is configured as above, videostream should be accesible over its GUI:

Screen Shot 2016-02-04 at 14.28.36

Part 1/3: Controlling LEDs using Raspberry Pi

In this post I will review, how to turn on or off LEDs using Raspberry Pi 2, Model B (RPi).

First we copy Raspbian linux to a microSD card, turn on RPi and connect to it using ssh.

We use three LEDs and each needs to be connected to each own positive supply of the circuit and ground. For the positive supply on RPi we use pins 18, 17 and 27 as seen on the scheme below:

RPi_GPIO

 

As the current would be too high if we connect the LED directly into the circuit, we need to add a resistor for each LED. As it is written in the Raspberry Pi spec, it can safely allow up to 16mA current. Our pins can supply 3.3V. Therefore to allow the LED to be the brightest, we can use 210Ohm  or stronger resistor. Using stronger resistor will result in the LED not being so bright.

In this example I am using 560Ohm resistor. I am also attaching a nice scheme for calculating the resistance of 4-band resistors:

Screen Shot 2016-02-04 at 11.09.35

 

To control a specific LED, we can “turn on” a specific LED using a Python library. First we need to set a pin as output and then we can turn it on (GPIO.HIGH) or off (GPIO.LOW). An example of a script that turns on a LED:

import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
 
GPIO.setup(18,GPIO.OUT)
GPIO.output(18,GPIO.HIGH)

Physical result:

IMG_0161

Databases Summer School at Kyungpook National University

During July 2015 prof. dr. Marko Bajec and I held a one-month summer school on databases and database design at the Kyungpook National University (KNU) in Daegu, South Korea. The summer school was selected among hundred applied summer school programs and 35 international students have applied for the course.

About KNU

KNU is the best national university in South Korea. Its main campus is located in Daegu, where we led the summer school at the IT department. The campus is very strong in electronics, although they offer also other studies. They have three more campuses across the country, which also focus on medicine. The KNU 365 Medical Center, located near Daegu, is a new complex with modern equipment. They also own a machine that is able to heal moving cancer tissue without damaging other parts of the body.

IMG_0778

The university has strong cooperation with local industries, such as Samsung, LG, Hyundai, Xinix, etc. They are very strong in the area of international affairs as they have some double degree programs with USA or EU universities. Slovene Faculty of Economics already has a double degree with KNU, while our faculty (Faculty for Computer and Information Science) will start offering the joint studies in 2015/2016.

About South Korea

South Korea is not that big country but still there live a lot of people and produce a large portion of electronic devices (Samsung, LG) or heavy industries (Hyundai) in the world. The only Slovene company that has headquarters in Korea is Kolektor, which we also visited in the industrial city of Gumi.

IMG_0786

I was surprised that mobile phones are more expensive than in Europe, that there were no options to buy cheap prepaids in supermarkets and also electronic departments in stores were not that huge. Later I found out that most of the Koreans order such devices online.

Koreans mostly drive cars made by their local manufacturers such as Hyundai or KIA. Also buses, trucks and other vehicles are made by these companies. It was especially interesting to see some car models that are not available in Europe and would be very competitive to European cars.

 

At first I thought the Korean food would be more Chinese or Thai -like, but they have their own cuisine. They adore chicken meat – especially with beer during different occasions :). Traditionally most important food is Kimchi – special cabbage with red spicy sauce, Bulgogi – slices of beef meat grilled together with vegetables, Gimbap – korean sushi with no fish, and some cold soups. I especially liked their Korean BBQ way of preparing food as you can grill ordered meat at a table. The only downside is that sometimes I was disappointed because of their low level of cleanliness in kitchens.

The most popular party drink is Soju. For real parties the youngsters mix it with beer. Apart from the plain 20% alcoholic drink it is produced with several flavours. Next, also rice wine Makgeolli is also popular – in my opinion of taste not that good.

Koreans are personally very calm and highly respect a societal hierarchy – professors are really respected by the students. I was feeling very safe and there were no incidents. Also streets are clean and nothing is damaged by the vandals. On the other hand, I was surprised that car drivers are not that polite as in northern EU countries.

I really enjoyed the stay in South Korea and am really grateful to our student assistant HyukSang Kwon and vice-president of international affairs at KNU Lorne Hwan, who made our stay even better.

My PhD Defense

I started my PhD directly after finishing my undergrad study, as a Junior Researcher from industry at Optilab and Laboratory for Data Technologies at the University of Ljubljana, Faculty for computer and information science. Throughout the study I was guided by my supervisor prof. dr. Marko Bajec, to whom I am very thankful for all his contributions to my work.

My core research area was a subfield of information retrieval, called information extraction. I especially focused into high-level information extraction tasks, such as named entity recognition, relationship extraction and coreference resolution. I proposed a novel approach for solving coreference resolution and relationship extraction. Moreover I connected all the three tasks into an iterative method that uses an ontology and enables end-to-end information extraction. All of the contribution were also published in scientific journals or presented at scientific conferences.

On monday, 22nd December 2014, I successfully defended my PhD thesis, which was approved by prof. dr. Zoran Bosnić, prof. dr. Dunja Mladenić and prof. dr. Marko Bajec. Below you can see a video of my defense or read my submitted thesis.

Video:

Thesis:

Gallery:

 

The end of Lajkbuk (previously Likebook) platform

In the early days of 2013 a friend of mine Dean Virant had an idea of developing a state-of-the-art platform for automatic organization of prize-games on Facebook. He invited me to be the technical lead and developer, while he was about marketing and sales. First, we were working on the Likebook app and later discovered that it is against the Facebook rules to name the platform like that. So, we bought another domain name, SSL certificate, … for the new name – “Lajkbuk” (i.e., slovene pronounciation of the word likebook in english). We also had many ideas, many initial design, but then we chose the most important features and selected the most user-centered design. While I was developing the application, Dean was reaching to our possible customers, which were at first slovene companies.

So, Lajkbuk is the platform that enables an organization to seamlessly organize a prize-game on Facebook. Next to the features of liking it also supports sharing counters and commenting by which consumers can improve their rank to get the reward. After the end of the game, we offered the organization to conduct some research about the users that participated in the games using the data with their consent. We had quite some successes in Slovenia and we have conducted a handful of successful games. Just as we wanted to broaden our support to other countries, multiple languages and automate the buying process, the Facebook anounced the prohibiton of organizing the games in such a way. So sadly, this is how the story with the Lajkbuk ends.

But the most important: We had an idea, we buit a solution, we sold some  games and made some people happy and obviously the time for new ideas has come …

Some technical details about the platform:

The whole source code (public part) is available on GitHub repository https://github.com/szitnik/Lajkbuk. The platform is developed as a JavaEE application using Spring Framework, Spring Social, Spring Data, Hibernate and other technologies. With a server certificate it ran on Tomcat 7.0, which was deployed in the DigitalOcean cloud using a domain name lajkbuk.si. The plaftorm was alive and fully functional from May 2013 to August 2014.

The main features are:

  • Facebook application: fully Facebook-connected with automatic login/registration, Facebook Tab Page integration, Sharing and Like logging, comment retrieval.
  • Admin pages: creating prize-games, entering customer data, consumer Facebook data retrieval.
  • Personal pages: my games and coupons to claim a reward.
  • Reports: according to our rules, a game can be ended prematurely for multiple reasons (organization does not follow rules, longer periods without activities).
  • Three possible features: COUPON, SHARE, COMMENT – used for winner selection and prize retrieval depending on our customer wishes.
  • And more …

Feel free to use the code!

Some screenshots: