Tuesday 4 November 2014

JWT usage example

Good, easy to understand JSON web token (JWT) usage example, which does not contain much unrelated stuff:
https://github.com/auth0/angular-token-auth

Article with explanation:
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/

Listings just in case if it suddenly disappear:

auth.server.js
var express = require('express');
var bodyParser = require('body-parser');

var jwt = require('jsonwebtoken');  //https://npmjs.org/package/node-jsonwebtoken
var expressJwt = require('express-jwt'); //https://npmjs.org/package/express-jwt


var secret = 'this is the secret secret secret 12356';

var app = express();

// We are going to protect /api routes with JWT
app.use('/api', expressJwt({secret: secret}));

app.use(bodyParser.json());
app.use('/', express.static(__dirname + '/'));

app.use(function(err, req, res, next){
  if (err.constructor.name === 'UnauthorizedError') {
    res.status(401).send('Unauthorized');
  }
});

app.post('/authenticate', function (req, res) {
  //TODO validate req.body.username and req.body.password
  //if is invalid, return 401
  if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
    res.status(401).send('Wrong user or password');
    return;
  }

  var profile = {
    first_name: 'John',
    last_name: 'Doe',
    email: 'john@doe.com',
    id: 123
  };

  // We are sending the profile inside the token
  var token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });

  res.json({ token: token });
});

app.get('/api/restricted', function (req, res) {
  console.log('user ' + req.user.email + ' is calling /api/restricted');
  res.json({
    name: 'foo'
  });
});

app.listen(8080, function () {
  console.log('listening on http://localhost:8080');
});


auth.client.js
var myApp = angular.module('myApp', []);

//this is used to parse the profile
function url_base64_decode(str) {
  var output = str.replace('-', '+').replace('_', '/');
  switch (output.length % 4) {
    case 0:
      break;
    case 2:
      output += '==';
      break;
    case 3:
      output += '=';
      break;
    default:
      throw 'Illegal base64url string!';
  }
  return window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
}

myApp.controller('UserCtrl', function ($scope, $http, $window) {
  $scope.user = {username: 'john.doe', password: 'foobar'};
  $scope.isAuthenticated = false;
  $scope.welcome = '';
  $scope.message = '';

  $scope.submit = function () {
    $http
      .post('/authenticate', $scope.user)
      .success(function (data, status, headers, config) {
        $window.sessionStorage.token = data.token;
        $scope.isAuthenticated = true;
        var encodedProfile = data.token.split('.')[1];
        var profile = JSON.parse(url_base64_decode(encodedProfile));
        $scope.welcome = 'Welcome ' + profile.first_name + ' ' + profile.last_name;
      })
      .error(function (data, status, headers, config) {
        // Erase the token if the user fails to log in
        delete $window.sessionStorage.token;
        $scope.isAuthenticated = false;

        // Handle login errors here
        $scope.error = 'Error: Invalid user or password';
        $scope.welcome = '';
      });
  };

  $scope.logout = function () {
    $scope.welcome = '';
    $scope.message = '';
    $scope.isAuthenticated = false;
    delete $window.sessionStorage.token;
  };

  $scope.callRestricted = function () {
    $http({url: '/api/restricted', method: 'GET'})
    .success(function (data, status, headers, config) {
      $scope.message = $scope.message + ' ' + data.name; // Should log 'foo'
    })
    .error(function (data, status, headers, config) {
      alert(data);
    });
  };

});

myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
  return {
    request: function (config) {
      config.headers = config.headers || {};
      if ($window.sessionStorage.token) {
        config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
      }
      return config;
    },
    responseError: function (rejection) {
      if (rejection.status === 401) {
        // handle the case where the user is not authenticated
      }
      return $q.reject(rejection);
    }
  };
});

myApp.config(function ($httpProvider) {
  $httpProvider.interceptors.push('authInterceptor');
});


index.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Angular Authentication</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
    <script src="./auth.client.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="UserCtrl">
      <span ng-show="isAuthenticated">{{welcome}}</span>
      <form ng-show="!isAuthenticated" ng-submit="submit()">
        <input ng-model="user.username" type="text" name="user" placeholder="Username" />
        <input ng-model="user.password" type="password" name="pass" placeholder="Password" />
        <input type="submit" value="Login" />
      </form>
      <div>{{error}}</div>
      <div ng-show="isAuthenticated">
        <a ng-click="callRestricted()" href="">Shh, this is private!</a>
        <br>
        <div>{{message}}</div>
        <a ng-click="logout()" href="">Logout</a>
      </div>
    </div>
  </body>
</html>


package.json
{
  "name": "angular-token-auth",
  "version": "0.1.0",
  "dependencies": {
    "body-parser": "^1.9.0",
    "express": "~4.9.0",
    "express-jwt": "~0.2.1",
    "jsonwebtoken": "~0.4.0"
  },
  "description": "Example of Token-based authentication in [AngularJS](http://angularjs.org) with [Express](http://expressjs.com).",
  "main": "auth.server.js",
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/auth0/angular-token-auth.git"
  },
  "keywords": [
    "angular",
    "auth",
    "jwt",
    "express"
  ],
  "author": "",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/auth0/angular-token-auth/issues"
  },
  "homepage": "https://github.com/auth0/angular-token-auth"
}

Wednesday 24 September 2014

Combine several Q objects programmatically with OR in Django ORM

Say we have dictionary coming from outside (from JSON, for example, containing some data to be used as OR clauses). It is possible to use __or__ to combine them programmatically.

from django.db import models
from operator import __or__ as OR
from django.db.models import Q

#... some code ...
clauses = [{'property':'name__exact','value':'andrew'},{'property':'name__icontains','value':'z'}, ... ]
or_params = []
for or_param in clauses:
    if 'value' in or_param.keys() and 'property' in or_param.keys():
        or_params.append(Q(**dict([(or_param['property'], or_param['value'])])))

Model.objects.filter(reduce(OR, or_params))

Many thanks to Calvin for right keywords

Wednesday 10 September 2014

Sencha: Catch all events of Observable

Very useful pattern to catch all events of Observable object in Sencha:
Ext.util.Observable.capture(object, function(){
    console.log(arguments);
});


This object might be Store, View, or whatever using Observable mixin. This may be useful to learn how the object work or to catch events before any other on/addListener listeners.

Arguments may wary but it contains at least two objects:
0: {String} always event name
1: {Object} object itself

This may contain other arguments such as Action, changed Model (for Store), String name of the action caused event, Array of changed fields (for Model and Store)

Store usage:
Ext.util.Observable.capture(store, function(){
    if (arguments[0]=='update') {
        /*eventName,store,record,operation,modifiedFields*/
        // Your fancy code here
        store.suspendEvent('update');
    }
});

Saturday 6 September 2014

Reading XLSX on android 4 (Post 3)

!!!UPDATE:
All this hacking is getting redundant with Android Build Tools 21+ and Android 5, please see this post for details: http://blog.kondratev.pro/2015/08/reading-xlsx-on-android-4-and-hopefully.html
-----------------


More on reading XLSX on Android.

I renamed "javax" namespace to "aavax" in StAX sources and recompiled it. After that I replaced all strings 'javax/xml/stream', 'javax/xml/namespace' and 'javax.xml.strings' occurrences in other binaries(including ooxml-schemas) to appropriate strings with "aavax". Now it works without necessity to use --core-library option!

Two previous posts:
http://blog.kondratev.pro/2014/08/reading-xlsx-on-android.html
http://blog.kondratev.pro/2014/09/further-to-my-post-from-yesterday-on.html

You can review demo project here:
https://github.com/andruhon/AndroidReadXLSX

You can download ported XSSX here:
https://github.com/andruhon/AndroidReadXLSX/tree/master/libs

Donate / help
I don't ask for a donation, but you can join me on the LinkedIN and endorse my Java and Android skills if you find this hack useful:
https://nz.linkedin.com/pub/andrei-kondratev/51/445/635

Tuesday 2 September 2014

Reading XLSX on android 4 (Post 2)

!!!UPDATE:
All this hacking is getting redundant with Android Build Tools 21+ and Android 5, please see this post for details: http://blog.kondratev.pro/2015/08/reading-xlsx-on-android-4-and-hopefully.html
-----------------

Further to my post from Saturday on reading XLSX on Android:

I shrunk dom4j, poi, poi-ooxml and xmlbeans into one jar with proguard. All classes not necessary for reading Excel files are seems to be removed. Proguard config follows:

-injars      {my IN jars mentioned above}
-outjars     poi-min.jar

-libraryjars {my dir with schemas}
-libraryjars {path to /jre/lib}
-libraryjars {path to /jdk/lib}

-dontoptimize
-dontobfuscate
-ignorewarnings

-keep class org.apache.poi.xssf.** { *; }
-keep class org.apache.poi.ss.** { *; }
-keep class org.apache.poi.hssf.** { *; }
-keep class org.apache.xmlbeans.** { *; }

It works fine for reading and writing both XLS and XLSX files.

Next post on XLSX:
http://blog.kondratev.pro/2014/09/reading-xlsx-on-android-3.html

Previous post on XLSX:
http://blog.kondratev.pro/2014/08/reading-xlsx-on-android.html

Sunday 31 August 2014

Reading XLSX on android 4 (Post 1)

!!!UPDATE:
All this hacking is getting redundant with Android Build Tools 21+ and Android 5, please see this post for details: http://blog.kondratev.pro/2015/08/reading-xlsx-on-android-4-and-hopefully.html
-----------------

Yesterday I committed XSSF Android usage demo to github:
https://github.com/andruhon/AndroidReadXLSX
The idea is in cleaning jars poi-ooxml and poi-ooxml-schemas from everything which is not necessary to read XLSX format. (just use ZIP archiver to manipulate classes inside, it works well)
This demo already contains reduced poi-ooxml-3.10-reduced.jar and poi-ooxml-schemas-3.10-reduced-more.jar and short building instructions.
Yep, you should use --core-library option to build this project. poi-ooxml depends on xmlbeans and both of them depends on some javax classes which are not available in android. So I have to use StAX library.
UPD: no need in --core-library option any more!

Other posts on reading XLSX on Android:
http://blog.kondratev.pro/2014/09/further-to-my-post-from-yesterday-on.html
http://blog.kondratev.pro/2014/09/reading-xlsx-on-android-3.html

Donate / help
I don't ask for a donation, but you can join me on the LinkedIN and endorse my Java and Android skills if you find this hack useful:
https://nz.linkedin.com/pub/andrei-kondratev/51/445/635

Thursday 7 August 2014

Getting rid of annoying Uncaught TypeError: Cannot read property 'isGroupHeader' of null

"Uncaught TypeError: Cannot read property 'isGroupHeader' of null" in sencha 4.x might be caused by nested grids usage. For example if you have grid with RowExpander rendering another grid into expander.

This happens because grid cell or cell editor event (mouseover, click or whatever) is fired in context of another grid (parent or ancestor).

This override might help (it works fine on 4.2.2 for me):

Ext.define('SystemFox.overrides.view.Table', {
    override: 'Ext.view.Table',
    checkThatContextIsParentGridView: function(e){
        var target = Ext.get(e.target);
        var parentGridView = target.up('.x-grid-view');
        if (this.el != parentGridView) {
            /* event of different grid caused by grids nesting */
            return false;
        } else {
            return true;
        }
    },
    processItemEvent: function(record, row, rowIndex, e) {
        if (e.target && !this.checkThatContextIsParentGridView(e)) {
            return false;
        } else {
            return this.callParent([record, row, rowIndex, e]);
        }
    }
});

Friday 16 May 2014

copy all GIT diff files on windows

Windows CMD one-line command to copy difference of two GIT commits into specific directory preserving directories hierarchy:

git diff --name-only yrc0m1 yrc0m2|sed s:/:\\:g > report.txt && for /F %F in ('cat report.txt') do xcopy %F c:\m1m2diff\%F && del report.txt

*xcopy will ask you to confirm wither the path is file or directory for each of your changed files. As far as diff returns only files changed, you can just do long F button press :-) Unfortunately I did not succeed to find a flag to suppress this warning with F option.

It consists of following subcommands:
1. git diff --name-only yrc0m1 yrc0m2 - returns list of changed files between commits yrc0m1 and yrc0m2;
2. sed s:/:\\:g - piped with | after previous one, converting Linux slashes to windows slashes;
3. > report.txt - oputput of previous two commands: all relative filepaths are saved in report.txt;
4. for /F %F in ('cat report.txt') do xcopy %F c:\m1m2diff\%F - iterates through lines in report.txt and copying file creating all not-existing directories from it's relative path (we suppose that c:\m1m2diff\ directory already exists)
5. del report.txt - simply deletes report.txt file.

Tuesday 29 April 2014

Running python along with PHP on Windows with Apache

Short howto:

1. Install Python on the server or your computer (adding Python.exe to the path)

2. download pre-compiled mod_wsgi.so from:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi
You should download right file for your Apache version and for your Python wersion:
for example mod_wsgi‑3.4.ap24.win32‑py3.4.zip is mod_wsgi.so for Apache 2.4 compiled as 32bit app and Python 3.4. This file works fine for me on XAMPP 1.8.0

3. Extract mod_wsgi.so into your /apache/modules/ directory (would be C:\xampp\apache\modules for XAMPP)

4. Add the following string into your /apache/conf/httpd.conf (somewhere among others LoadModule strings):
LoadModule wsgi_module modules/mod_wsgi.so

5. Say you want your Python stuff to work on URL http://localhost/my-python-stuff/:
Create /my-python-stuff/ directory inside of your localhost's public_html dir (/htdocs/localhost/www/ for XAMPP);
Create .htaccess and index.wsgi files in this directory;

.htaccess
Options +ExecCGI AddDefaultCharset utf-8  #add wsgi handler AddHandler wsgi-script .wsgi  #redirect all requests to index.wsgi RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.wsgi/$1
index.wsgi
def application(environ, start_response): status = '200 OK' output = 'Hello World!' response_headers = [('Content-type', 'text/plain'), ('Content-Length', str(len(output)))] start_response(status, response_headers) return [output]
Now if you re-start/run your apache/XAMPP and open http://localhost/my-python-stuff/ , or any other URL deeper than /my-python-stuff/ (/my-python-stuff/test/ and so on), you will see Hello World message in your browser.