Hackviking He killed Chuck Norris, he ruled dancing so he took up a new hobby…


Implementing Google OAuth in JSFiddle


The implementation of Google OAuth for use with there API's are simple with there API Client Library for JavaScript, if you are developing a normal webpage. If you want the functionality in a JSFiddle it's a little more complex for several reasons. I have put together a demo on JSFiddle that shows how it can be accomplished!


I wanted to be able to include Google Oauth for API access in demos I create on JSFiddle. I did a few tests with the API Client Library for JavaScript provided by Google. Ran into several issues with cross-site limitations and sandboxing. Since JSFiddle runs in i sandboxed iframes it limits access to navigation, URL reading and other stuff that the client.js relies on to authenticate the user and get the token back. I found that if the user is already authenticated with Google and you set the immediate parameter to true it will work. That's probably good enough for several demos but it's not a clean solution so I spent a few hours and came up with a solution. If the user isn't already authenticated two new tabs will open up and nothing more will happen.


You need to setup a project in the Google Cloud Platform Console and get the clientID. You also need to setup Authorized redirect URIs that matches your JSFiddle. Due to the iframe nature of JSFiddle you cant use the jsfiddle.net address, since the result frame being served from the fiddle.jshell.net domain. For this demo I setup these two redirect URIs:

One address for the case of direct access to the fiddle (someone fining it via Google for example) and one if they navigate to it from my dashboard.

To get this to work I implemented the OAuth flow from the ground up. The demo uses jquery, because it's easier, but it can be done in pure JavaScript if you want to. I'm using the standard Oauth 2 flow were you send the user to Google for login with your client_id, redirect_uri and scope as query string parameters. The user authenticates with Google and get's redirected back to the provided redirect_uri with access_token, token_type and expires_in parameters as query string parameters. Google OAuth supports redirecting the user back to a http address but that's no good from a security standpoint! JSFiddle does support https on all it's fiddles so let's make use of it!

Different then a standard JSFiddle

There are a few things that are different from a regular JSFiddle implementation, to create a safe demo that handles the iframe limitations.

  • Check for HTTPS
    This is just for making the demo safe. When Google returns the user to the site with the token as query string parameter it is possible to intercept if you don't use HTTPS. A simple implementation of location.protocol == 'https:' checks if we are secure or not. This isn't needed since you can send the user from a HTTP site to Google and get the user back on a HTTPS redirect. This is just put there to make a point of the HTTPS implementation.
  • The use of fiddle.jshell.net instead of jsfiddle.net
    Since the iframe with the result, where all the javascript is executed, is served from fiddle.jshell.net all the content needs to be served from there. If not the script cant access the parent frame URL containing the access token returned from Google.

Points of interest in the code

  • Check for HTTPS
    As above this isn't really needed since I can set the redirect_uri to whatever address I want as long as it's specified in the cloud console.
  • Create the authentication link
    For this to work properly it needs to be a target="_blank" link. Navigation inside the iframe is blocked outside the jsfiddle domains. This is the reason why the demo needs to open a new tab to be able to return with the access token. The parameters at the top will set the basic information for building the link:

    var oAuthEndPoint = "https://accounts.google.com/o/oauth2/auth";
    var oAuthClientID = "702841265150-iaravt3jmu0c67k892pivj9kgkb8dbco.apps.googleusercontent.com";
    var oAuthScope = "https://www.googleapis.com/auth/userinfo.profile";

    Then we build the redirect uri from the current JSFiddle address. I implemented it this way to make it easy to fork it to create other demos based on this implementation. I use the a element for easy manipulation of the domain and path. Replacing the protocol and domain with https://fiddle.jshell.net:

    var a = document.createElement('a');
    a.href = document.referrer;
    var redirect_uri = ['https://fiddle.jshell.net', a.pathname].join('');
    a = '';

    document.referrer is used to get the actual address of the fiddle from the parent frame, even if the domains doesn't match at this point. An easy way to get around the same origin limitations of the iframe.

  • User clicks the authentication link/button
    The user is sent to Google to authenticate and allow the app access to the user information. The only scope requested in this demo is basic profile information.
  • User is returned to JSFiddle
    When the user is returned the fiddle will load all over again. So each time it loads it will check if HTTPS is used, if so check for the URL parameter access_token. This is why we need to use the fiddle.jshell.net domain, it will make all the iframes of the fiddle to load from the same domain giving our script access to it's parent. We need that access to grab the URL and extract the parameters. This function grabs different parameters from the URL of the parent frame:

    function GetURLParameter(sParam) {
        var sPageURL = window.parent.location.hash.substring(1);
        var sURLVariables = sPageURL.split('&');
        for (var i = 0; i < sURLVariables.length; i++) {
            var sParameterName = sURLVariables[i].split('=');
            if (sParameterName[0] == sParam) {
                return sParameterName[1];
  • Use the token for API access
    As soon as we have the token we can use that for accessing the API with a simple ajax request via this simple function:

    function LoadUserInfo(access_token, expires_in) {
            url: 'https://www.googleapis.com/userinfo/v2/me',
            type: 'GET',
            dataType: 'json',
            headers: {
                'Authorization': 'Bearer ' + access_token
            success: function (data) {
                // Hide login
                // Populate demo, img and name
                $("#user_pic").attr("src", data.picture);
                $("#user_name").attr("href", data.link);
                // Show raw data
                for (var property in data) {
                    if (data.hasOwnProperty(property)) {
                        $("#raw_data").append("<b>" + property + "</b>" + data[property] + "<br/>");
                // Display demo
            error: function () {
                $('#demo').html('<p>An error has occurred</p>');


So there are a few limitations with this approach. You get the token that is valid for 3600 seconds (one hour) and implementing code for renewing that with out losing state is not possible. So if the user have started creating something and the token expires renewing it will end up in a reload of the fiddle. The other, smaller limitation, is that there always will be a second tab opened to authenticate the user.

You also need to set the code as base in the fiddle at all times, redirects to a version number like /3 will make the redirect back from Google to fail!

Any thoughts, questions or suggestions? Please share in the comments below!

Complete JSFiddle demo


Embed image in HTML code


You can embed images straight into HTML code without loading a separate image file. This is called data URL and is a base 64 encoded representation of the actual image file. You can more or less embed what ever data you like this way but the only implementations I have seen so far is with images. So why do this? There are probably hundreds of examples where this can be useful, I have used it for:

  • For taglines on services like JSFiddle, where external hosting of files can be a mess. If I delete the file or my server is down my JSFiddle demos will be broken.
  • E-mail signatures, same thing here no dependence on external servers for serving images in my mail signature. Some e-mail clients out there doesn't display data URL's so be careful with this one.
  • Screenshots in documentation distributed with software. Since the file is loaded from the users local hard drive the bigger size (see below) isn't an issue for any image and I only have to distribute on HTML file with the complete documentation.

So why isn't every image put into HTML this way? The answer is simple, the size increases! For small images, usually part of the layout, can be loaded faster even though the size is increased. This is due to the lack of overhead from an additional http request to get the image file. Every time someone opens an HTML page over the internet the browser then open new http connections for each resource referenced in the HTML like images, css and javascript files. So by cutting down on the number of request the page can load faster.

Dataurl.net by Sveinbjorn Thordarson is a really good resource to check what files on your site that would be suitable for data url embeds.

Simple example of a base 64 encoded data url image, my tagline image:

<img class="brand-img" alt="Kristofer Källsbo aka Hackviking"    src="data:image/jpeg;base64,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">

This code will result in this:
Kristofer Källsbo aka Hackviking

I put together a JSFiddle with some example code for converting images to base 64 encoded data url's using HTML5 components and plain javascript:


Win32 Disk Imager

Win32 Disk Imager main window

Reading and writing images to SD cards made easy! I more or less us it every day to write images to SD cards for my Raspberry Pi projects or for doing a backup of them. Win32 Disk Imager has received some bad press because it some times breaks SD cards. Every time that happen to me it was the image that was bad, so I can not really agree with the bad comments. If the card becomes unreadable it's easily fixed with SD Formatter. Win32 Disk Imager can be downloaded from SourceForge!


SD Formatter

SD Formatter main window

SD cards some times seem to shrink or just get unreadable. Most of the time there is nothing wrong with them at all. They have just been written to in a bad way that messes up the partition table or breaks it all together. Most of the time you can fix it with disk management tools but it's more work then needed. I usually get problems with my SD cards from bad images for my Raspberry Pi but even my GoPro camera messed up a card ones. I also use a Denver action cam that usually formats the SD card with a smaller partition then the actual card size. SD Formatter from SD Association fixes the cards every time. Just run it against the card and turn on "format size adjustment" and it will come out just fine.


Raspberry Pi as a torrent server


A Raspberry Pi is a great for creating an always on torrent box that can take care of all your downloading and seeding. If you combine it with a NAS and a Raspberry Pi Kodi media center you will have a really sweat setup. The Raspberry Pi has a low power consumption, I run my of the USB port on my NAS. It also have no fans so it's quiet! In this guide we setup Transmission on a Raspberry Pi which includes both a web gui and third party apps for IOS and Android.

I presume that you have some basic knowledge of Linux and the Raspberry Pi. If not you might need to check out the installation guide for Raspberry Pi. When you have your Raspberry Pi up and running just follow the guide below. Use an image and not NOOBs it will come back and haunt you!
Continue reading...


Raspbian: fstab doesn’t mount NFS on boot


Ran out of disc space in one of my Raspberry Pi projects last night. Of course I did a quick and dirty install with NOOBs so cloning to a larger SD-card felt like a drag. So I decided it was time to upgrade from a 4GB SD to a 16GB SD as well as the latest version  4.1.6+. Installation went like a charm until I went to edit my /ect/fstab. I added the same NFS line as I used before: /mnt/download nfs rsize=8192,wsize=8192,timeo=14,intr 0 0

sudo mount -a work just fine but the share wasn't mounted after reboot. Googled the issue and found a lot of different suggestions, many related to USB drives. The number one suggestion was adding rootdelay=10 or rootdelay=5 to /boot/cmdline.txt. That would probably solve the issue for USB drives because the system are unable to identify the drive that early in the boot. Same suggestion was given for NFS failures as well but will not work. Tried a lot of suggestions, even found scripts to run mount -a after boot. That is not a solution just a work around!

Suggestion for adding x-systemd.automount,noauto to the mount options failed as well. Tried a lot of different configurations with one thing in common, no error in /var/log/syslog.

Finally I realized that the network was not ready! I checked the /etc/network/interfaces settings for eth0.

iface eth0 inet manual

It will still get a DHCP address but that will happen later in the boot process. So when the fstab entries are processed there is no network connection and therefore the disc will not mount. So if you change it to:

iface eth0 inet dhcp

Then the NFS drive will mount just fine after a reboot.


TFTPD32/64 a must have in the toolbox


TFTPD32 (or the 64bit version) is a great tool when working with networking, built in systems or small computers like the Raspberry PI. I usually end up using it's DHCP function when I need to connect something directly to my laptop for testing. It's also a great tool for quickly setting up a TFTP server for flashing firmware in built in systems. TFTPD also includes a syslog server which comes in handy troubleshooting linux based network devices like switches, routers and other stuff. Of course it's a great tool during penetration testing with man in the middle attacks where you want to take over the DHCP function in the network. I have been using it for years and I really recommend it!

TFTPD is written by Philippe Jounin, I think he is from France. Don't let the poor website design scare you of the tools he put out is really great! So check out his website: http://www.jounin.net/tftpd32.html



Easiest way to embed assembly’s into your executables

I usually write a lot of command line tools for different quick fixes. Distributing them to clients with a lot of attached DLL files are not always the best. They get copied around different servers and sooner or later someone runs them without the proper DLL files present. For quick and dirty tools there might be faulty error handling and the tool fails in a critical moment due to the missing assembly. I usually embed the DLL file into the executable, especially when doing command line tools. By far the easiest way of doing that in .Net is to install a Nuget package called Costura.Fody!

Just install it into the project and build the release and all assembly's get compressed and embedded into the executable. Visit Costura.Fody github page for more information!


WebRTC vulnerability exposes VPN users


It's now easy to expose the true IP address of VPN users. Daniel Roesler published the an example howto exploit the bug on Github. Firefoz, Mozilla, Chroma and Internet Explorer (with WebRTC plugin) are vulnerable to this bug. WebRtc is used for peer-to-peer connections for video chat and other similar implementations.

If the user isn't using VPN the computers internal network address will be exposed. This implementation is used for the WebRtc to handle NAT on the network and be able to bind sessions to the public IP. However the bug is really nasty because it exposes these functions to javascript. So this entire implementation below is made with javascript. The request is not registered in the developer console and can not be blocked by plugins.

If the user is using a lightweight VPN client, like a chrome plugin, the VPN will be bypassed all together and both the real public IP and internal NAT address will be shown.

Below there is a demo, if you see your public and private IP your browser is vulnerable for this exploit.

Code cred: Daniel Roesler (I only modified it to run in WordPress).

Your local IP addresses:

    Your public IP addresses:

      function getIPs(){
          var ip_dups = {};
          //compatibility for firefox and chrome
          var RTCPeerConnection = window.RTCPeerConnection
          || window.mozRTCPeerConnection
          || window.webkitRTCPeerConnection;
          var mediaConstraints = {
              optional: [{RtpDataChannels: true}]
          //firefox already has a default stun server in about:config
          // media.peerconnection.default_iceservers =
          // [{"url": "stun:stun.services.mozilla.com"}]
          var servers = undefined;
          //add same stun server for chrome
              servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
              //construct a new RTCPeerConnection
              var pc = new RTCPeerConnection(servers, mediaConstraints);
              //listen for candidate events
              pc.onicecandidate = function(ice){
              //skip non-candidate events
                  //match just the IP address
                  var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3})/
                  var ip_addr = ip_regex.exec(ice.candidate.candidate)[1];
                  //remove duplicates
                  if(ip_dups[ip_addr] === undefined)
                      var li = document.createElement("li");
                      li.textContent = ip_addr;
                      //local IPs
                      if (ip_addr.match(/^(192\.168\.|169\.254\.|10\.|172\.(1[6-9]|2\d|3[01]))/))
                      //assume the rest are public IPs
                          ip_dups[ip_addr] = true;
          //create a bogus data channel
          //create an offer sdp
              //trigger the stun server request
              pc.setLocalDescription(result, function(){}, function(){});


      Amazon EC2 Linux – Add additional volumes

      EBS Mappings

      Adding additional storage to your Amazon EC2 instance have several advantages. You can select the right storage type for the use. Why use a fast SSD backed volume for storing nightly backups instead of magnetic storage, that ar slower but come at a much lower price.

      First you need to provision storage and assign it to your instance. Amazon provides a good guide on how to add additional volumes to your instances. There are several advantages to using several different volumes. As I wrote in my guide to move mysql storage you will not risk running the boot disk full witch will make the system halt. Other advantages include the selection of storage fit for your purpose and price range, as mentioned above. External volumes can also easily be migrated between instances if and when you get a need for that. It is also easier when you need to extend your storage space. Instead of making a snapshot of the entire instance and then launching a new one with a bigger drive you can attach new storage and migrate the data. This approach will make the downtime much shorter.

      When selecting the correct storage for you solution there are a few things to keep in mind. When it comes to EBS it comes in three basic flavors. All with there benefits and disadvantages, it is there for important to make an educated decision.
      Continue reading...