Wednesday, October 30, 2013

AngularJS ng-option with IE8

IE always make our life a bit challenging. especially with AngularJS ng-option, it won't refresh the options unless we trigger it by modify the options content. I guess this is the rendering issue in IE8, it try to compare the reference instead of the value. Here is the code snippet if you need it.
/**
* General-purpose Fix IE 8 issue with parent and detail controller.
* @example <select sk-ie-select="parentModel">
*
* @param sk-ie-select require a value which depend on the parent model, to trigger rendering in IE8
*/
app.directive('ieSelectFix', [
function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attributes, ngModelCtrl) {
var isIE = document.attachEvent;
if (!isIE) return;
var control = element[0];
//to fix IE8 issue with parent and detail controller, we need to depend on the parent controller
scope.$watch(attributes.ieSelectFix, function() {
//this will add and remove the options to trigger the rendering in IE8
var option = document.createElement("option");
control.add(option,null);
control.remove(control.options.length-1);
});
}
}
}
]);
view raw ie8SelectFix.js hosted with ❤ by GitHub

Friday, October 18, 2013

AntiXSS for Web API

Most people forget to protect their site from XSS attack.
They simply accepting the fact that the smart javascript libary (AngularJS) will protect them by escaping the json characters.

But how about your legacy site, it still allow your XSS script to harm innocent user.

Unfortunately AntiXSS library doesn't protect you with Double open angle brackets which can pass this script in especially if the client use firefox.

//Double open angle brackets
//Using an open angle bracket at the end of the vector instead of a close angle bracket causes different behavior in Netscape //Gecko rendering. Without it, Firefox will work but Netscape won't:
<iframe src=http://ha.ckers.org/scriptlet.html <
Here is the complete snippets

using Microsoft.VisualStudio.TestTools.UnitTesting;
using SEEK.Employment.Profile.API.Validation;
public class AntiXssValidator : IAntiXssValidator
{
public static string[] XSSTagStringsForDoubleOpening = {"iframe",
"script",
"style",
"input"
};
/// <summary>
/// Validate the words which contains potential XSS Attack.
/// This will compare the encoded with sanitize html fragments, if it finds any differences means that it contains unsafe html tags.
/// Here is the least of potential XSS attacks
/// https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
/// </summary>
/// <param name="words"></param>
/// <returns></returns>
public bool Validate(string words)
{
if (string.IsNullOrEmpty(words))
{
return false;
}
//this will protect all this script attack list https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
var sanitizedWords = Sanitizer.GetSafeHtmlFragment(words);
var sanitizedWordsDecoded = HttpUtility.HtmlDecode(sanitizedWords);
//compare the sanitizedWord to check whether there is invalid tag
if (sanitizedWordsDecoded != words)
{
return true;
}
//except this one, we should protect againts Double open angle brackets
var checkWords = words.ToLower().Trim().Replace(" ", ""); //take out all space to protect < iframe
return XSSTagStringsForDoubleOpening.Any(tag => checkWords.Contains("<" + tag));
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SEEK.Employment.Profile.API.Validation;
[TestClass]
public class MaliciousCharactersValidatorTests
{
private IAntiXssValidator validator;
[TestMethod]
public void Validate_WithMaliciousCharacters_ReturnsTrue()
{
string wordsToValidate = "<script>";
validator = new AntiXssValidator();
bool result = validator.Validate(wordsToValidate);
Assert.IsTrue(result);
}
[TestMethod]
public void Validate_WithoutMaliciousCharacters_ReturnsFalse()
{
string wordsToValidate = "abcdefghijklomnopqrstuvwxyz0123456789~!@#$%*()";
validator = new AntiXssValidator();
bool result = validator.Validate(wordsToValidate);
Assert.IsFalse(result);
}
[TestMethod]
public void Validate_WithNullString_ReturnsFalse()
{
string wordsToValidate = null;
validator = new AntiXssValidator();
bool result = validator.Validate(wordsToValidate);
Assert.IsFalse(result);
}
[TestMethod]
public void Validate_WithEmptyString_ReturnsFalse()
{
string wordsToValidate = string.Empty;
validator = new AntiXssValidator();
bool result = validator.Validate(wordsToValidate);
Assert.IsFalse(result);
}
[TestMethod]
public void Validate_ShouldAllowLessAndGreaterThanCharacter()
{
string wordsToValidate = "managing < 5 people";
validator = new AntiXssValidator();
bool result = validator.Validate(wordsToValidate);
Assert.IsFalse(result);
}
[TestMethod]
public void Validate_ShouldBlockDoubleOpeningMaliciousTag()
{
string wordsToValidate = "<iframe script <";
validator = new AntiXssValidator();
bool result = validator.Validate(wordsToValidate);
Assert.IsTrue(result);
}
}

Thursday, October 17, 2013

AngularJS Placeholder for IE8/9 + Validation

After 5 hours looking how to fix IE8 bug with placeholder and required attribute,
I manage to find the problem and the solution.

The key problem is that our $formatter is executed before the model binder finish loading.
which caused the placeholder to be applied as a value.
You can guess, this lead to by passing your required validation.

So the key solution is to let the model binder finish their work first and then we do watermark of our control.

Key of the day : $timeout

Feel free to see the whole angular placeholder from my gist
https://gist.github.com/kkurni/7018564
MyApp.directive('placeholder', function($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
//check whether it support placeholder and cache it
scope.supportsPlaceholders = scope.supportsPlaceholders || function() {
return "placeholder" in document.createElement("input");
};
if (scope.supportsPlaceholders()) {
return;
}
//this function is used to move the caret to the left
var caretTo = function(el, index) {
if (el.createTextRange) {
var range = el.createTextRange();
range.move("character", index);
range.select();
} else if (el.selectionStart != null) {
el.focus();
el.setSelectionRange(index, index);
}
};
var setPlaceholder = function () {
element.val(attr.placeholder)
};
var clearPlaceholder = function () {
element.val('');
};
element.bind('focus', function() {
//on focus, set the caret into 0 position
if (element.val() == attr.placeholder) {
caretTo(element[0], 0);
}
});
element.bind('click', function() {
//on click, set the caret into 0 position
if (element.val() == attr.placeholder) {
caretTo(element[0], 0);
}
});
element.bind('keydown', function(event) {
//disable left or right key code when there is placeholder
if (element.val() == attr.placeholder) {
if (event.keyCode == 37 || event.keyCode == 39) {
event.preventDefault();
}
}
});
element.bind('keypress', function() {
//on key press, clear the placeholder
if (element.val() == attr.placeholder) {
clearPlaceholder();
}
});
element.bind('blur', function () {
//on blur, we just set the placeholder if there is no value
if (element.val() == '') setPlaceholder();
});
//formatter is executed when the model is changed
ctrl.$formatters.unshift(function (val) {
if (!val) {
//this timeout is needed so that the validation can finish their binding before we put our placeholder value
$timeout(function(){
setPlaceholder();
return attr.placeholder;
});
}
return val;
});
}
};
});
describe('placeholder', function() {
var element, $scope, $timeout, $compile;
beforeEach(module('MyApp'));
beforeEach(angular.mock.inject(function($rootScope, _$compile_, _$timeout_) {
$scope = $rootScope.$new();
$timeout = _$timeout_;
$compile = _$compile_;
$scope.supportsPlaceholders = function() {
return false;
};
element = angular.element('<input type="text" placeholder="enter placeholder" ng-model="model" />');
$compile(element)($scope);
$scope.$digest();
$scope = element.scope();
}));
describe('$formatter', function() {
it('should set element value to placeholder if model is undefined', function() {
$timeout.flush();
expect(element.val()).toEqual('enter placeholder');
});
it('should set element value to model value if model is defined', function() {
$timeout.flush();//flush the first time out
$scope.model = 'some model';
$compile(element)($scope);
$scope.$digest();
expect(element.val()).toEqual('some model');
});
});
describe('on keypress', function() {
it('should clear element value if it is the same as a placeholder', function() {
element.triggerHandler('keypress');
expect(element.val()).toEqual('');
});
});
});

Wednesday, October 16, 2013

Telerik Icenium first impression

An evolution of mobile development trends will demand cross development platform.
There are heaps of new technology out there which make this idea close to reality.
Besides PhoneGap, Titanium, Monotouch, Today I will share my first impression with Telerik Icenium.


What is Icenium ?
A Platform for Hybrid Mobile Development which includes IDE, Simulator, Debugging Tools and Publishing.


IDEs
  • Icenium Graphite - Windows IDE
  • Icenium Mist - Cloud IDE
  • Visual Studio Extension


First Impression
This new platform sound promising and it definitely make development easier and cheaper to maintain.
However there are some minor limitation which may not effect your decision to start using Icenium such as Icenium Mist which is their cloud IDE is still buggy.
This is nice to have gimmick but mostly developer will prefer to work on their own local IDE. It asked me to wait for compiling the code which should be expected to be quicker overtime.



Sample code
Here are my sample code if you want to have a quick look



Goodies
I love their idea to quick deploy to IOS device.
They use QR Code to wrap the link and will deploy into icenium ion container.

Saturday, October 05, 2013

Podcast project

Here is my podcast project dedicated for my lovely church.

Features :
* Searchable through ITunes



* Embedded player

* Fully CMS Website

Wednesday, October 02, 2013

Face detection using R

I just started to use cool statistic programming language tool called R.

Here is the example to do face detection.
https://gist.github.com/kkurni/6789379

The tricky part is how do you manage your memory for big processing data.

Suddenly my machine become very slow to me.
I will laverage AWS or google cloud machine for my dev machine