romama
Saturday, 9 July 2011
It's Friday I'm In Love
I am building a new service, which is going to be Events.
While doing so, I came across some interesting question: how to get the client culture settings?
Because I want to know which day is the first day of the week in my user's world.
Turns out all you have to do is to setup your page so that it gets these settings automatically,
and attaches them to the current thread.
So I set up my calendar so that my first day of week is Tuesday (which is kind of true).
But still, my thread current culture (Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek) says it is Monday.
Turns out you don't get the complete culture info from the client, which actually makes sense. Instead, you get the preferred language chosen in the user's browser settings, which is used to determine the culture settings.
Change it to en-US and you'll get Sunday.
Yes, you can see the skeleton of calendar on the background.
While doing so, I came across some interesting question: how to get the client culture settings?
Because I want to know which day is the first day of the week in my user's world.
Turns out all you have to do is to setup your page so that it gets these settings automatically,
<%@ Page Title="Events" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="Events.aspx.cs" Inherits="romama.Calendar.Events" ClientIDMode="Predictable"
UICulture="auto" Culture="auto" %>
So I set up my calendar so that my first day of week is Tuesday (which is kind of true).
But still, my thread current culture (Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek) says it is Monday.
Turns out you don't get the complete culture info from the client, which actually makes sense. Instead, you get the preferred language chosen in the user's browser settings, which is used to determine the culture settings.
Change it to en-US and you'll get Sunday.
Yes, you can see the skeleton of calendar on the background.
Tuesday, 5 July 2011
Search!
So now with the search. Search is performed by tags only, because text is stored encrypted.
Note titles are not encrypted, but they are not considered so far.
Sunday, 3 July 2011
Client encryption: final version
function getKey()
{
var key = localStorage.PBK;
if (!key)
{
var password = prompt("Enter data encryption key. Please do not use your password!");
if (!password) { return key; }
var p = {};
p.iter = 1000;
p.salt = [0xD1F6D8FF, 0x482648A7];
key = sjcl.misc.cachedPbkdf2(password, p).key.slice(0, 4);
localStorage.PBK = key;
}
return key;
}
function encryptElements()
{
var key = getKey();
if (!key || !key.length) return;
$(".cryptable").each(
function (idx)
{
if ($(this).val() && !$(this).val().match(/\{iv\:".*",salt\:".*",ct\:".*"\}/))
{
try
{
$(this).val(sjcl.encrypt(key, $(this).val()));
}
catch (e)
{
error("Cannot encrypt: " + e);
return false;
}
}
}
);
return true;
}
function decryptElements()
{
var key = getKey();
if (!key || !key.length) return;
$(".cryptable").each(
function (idx)
{
if ($(this).val() && $(this).val().match(/\{iv\:".*",salt\:".*",ct\:".*"\}/))
{
try
{
$(this).val(sjcl.decrypt(key, $(this).val()));
}
catch (e)
{
// could not decrypt, data will be shown as is.
}
}
}
);
}
It is not totally safe because anyone who has an access to the local machine can obtain the key from the local storage, but it satisfies my needs: as a provider of a service, I will not be able to see the user data, even myself.
Saturday, 2 July 2011
There is your problem
So, after 2 days of struggling with Chrome, I finally figured out the reason why my client encryption didn't work there.
This is the simple page which shows the issue:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test validate</title>
<script type="text/javascript">
//<![CDATA[
function validate()
{
var t = document.getElementsByTagName("textarea");
for (var i = 0; i < t.length; i++)
{
alert("Text: " + t[i].innerHTML);
}
return false;
}
//]]>
</script>
</head>
<body>
<form method="post" id="a" action="test.htm" onsubmit="return validate();">
<textarea type="text" name="myTextArea" rows="2" cols="20" id="myTextArea">Some text</textarea>
<input type="submit" name="myButton" value="Submit" id="myButton" />
</form>
</body>
</html>
We have a form with textarea and we want to do something with the textarea modified text before the form is submitted to the server. This can be validation, or encryption, as in my case, or anything else.
The script from the example works perfectly fine in IE8. InnerHTML returns the actual up-to-date text, reflecting all the changes user made before pressing "Submit" button. So does InnerText, textContent and $(this).text().
However, what I get in Chrome is always the text as it was when the form was initially loaded. Changes are simply not there. Neither they can be obtained through InnerText, textContent or $(this).text().
Surprisingly, if I use technically non-existing "value" property, I do get the latest changes, as in IE, so in Chrome.
Using "value" property seem to solve the problem, at least for IE8 and Chrome, except I cannot use jQuery selector anymore, because object returned by $(this) does not have this property.
Client encryption, new version:
function encryptElements()
{
var cryptable = getElementsByClassName("cryptable");
var len = cryptable.length;
for (var i = 0; i < len; i++)
{
cryptable[i].value = sjcl.encrypt("password", cryptable[i].value);
}
return true;
}
function decryptElements()
{
$(".cryptable").each(
function (idx)
{
if ($(this).text())
{
$(this).text(sjcl.decrypt("password", $(this).text()));
}
}
);
}
decryptElements();
Now I need to decide where to store the password.
UPD: Thanks to my smarter colleague, I figured out I can use $(this).val() and achieve the result I need.
So now it look like that:
This is the simple page which shows the issue:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test validate</title>
<script type="text/javascript">
//<![CDATA[
function validate()
{
var t = document.getElementsByTagName("textarea");
for (var i = 0; i < t.length; i++)
{
alert("Text: " + t[i].innerHTML);
}
return false;
}
//]]>
</script>
</head>
<body>
<form method="post" id="a" action="test.htm" onsubmit="return validate();">
<textarea type="text" name="myTextArea" rows="2" cols="20" id="myTextArea">Some text</textarea>
<input type="submit" name="myButton" value="Submit" id="myButton" />
</form>
</body>
</html>
We have a form with textarea and we want to do something with the textarea modified text before the form is submitted to the server. This can be validation, or encryption, as in my case, or anything else.
The script from the example works perfectly fine in IE8. InnerHTML returns the actual up-to-date text, reflecting all the changes user made before pressing "Submit" button. So does InnerText, textContent and $(this).text().
However, what I get in Chrome is always the text as it was when the form was initially loaded. Changes are simply not there. Neither they can be obtained through InnerText, textContent or $(this).text().
Surprisingly, if I use technically non-existing "value" property, I do get the latest changes, as in IE, so in Chrome.
Using "value" property seem to solve the problem, at least for IE8 and Chrome, except I cannot use jQuery selector anymore, because object returned by $(this) does not have this property.
Client encryption, new version:
function encryptElements()
{
var cryptable = getElementsByClassName("cryptable");
var len = cryptable.length;
for (var i = 0; i < len; i++)
{
cryptable[i].value = sjcl.encrypt("password", cryptable[i].value);
}
return true;
}
function decryptElements()
{
$(".cryptable").each(
function (idx)
{
if ($(this).text())
{
$(this).text(sjcl.decrypt("password", $(this).text()));
}
}
);
}
decryptElements();
Now I need to decide where to store the password.
UPD: Thanks to my smarter colleague, I figured out I can use $(this).val() and achieve the result I need.
So now it look like that:
function encryptElements()
{
var key = getKey();
if (!key || !key.length) return;
$(".cryptable").each(
function (idx)
{
if ($(this).val() && !$(this).val().match(/\{iv\:".*",salt\:".*",ct\:".*"\}/))
{
try
{
$(this).val(sjcl.encrypt(key, $(this).val()));
}
catch (e)
{
error("Cannot encrypt: " + e);
return false;
}
}
}
);
return true;
}
Subscribe to:
Comments (Atom)






