In our email, we see the footer font-size is not as we expected even if I specified !important in inline style. After google a bit, it turns out there is property called text-size-adjust to controle this. By default, Apple Mail’s minimum font size comes into play on the iPhone and iPad. By adding the this property to your CSS styles (text-size-adjust: 100% or none), you can
override the default font sizes on Webkit-based email clients, thus
avoiding layout glitches on the iPhone and iPad:
As this property is non-standard, it must be used prefixed: -moz-text-size-adjust, -webkit-text-size-adjust, and -ms-text-size-adjust.
If -webkit-text-size-adjust is explicitely set to none, Webkit-based desktop and tablet browsers, like Chrome or Safari, instead of ignoring the property, will prevent the user to zoom in or out the Web page.
https://developer.mozilla.org/en-US/docs/Web/CSS/text-size-adjust
Email template seems a piece of cake, but it is indeed not. We should be patient to use old school HTML coding skills and use popular email campaign tools to verify and test it.
Don't forget the followings:
1. Image styles
2. W3C HTML validator
3. Table for structures
4. Inline styles, no short-cut CSS
5. Testing across email clients
https://litmus.com/interactive-testing
https://templates.campaignmonitor.com/build/
https://litmus.com/blog/16-tips-troubleshooting-html-email
http://www.ruanyifeng.com/blog/2013/06/html_email.html
Tuesday, September 24, 2013
Monday, September 9, 2013
Javascript replace all line breaks in a string with
- str = str.replace('\n', '<br />'); -> However, this only replace the first ocurrence
- str = str.replace(/\n/g, '<br />'); -> use regexp to do global match
- str.replace(new RegExp('\n','g'), '<br />') -> similar to #2, but use constructor to build RegExp
- str = str.split("\n").join("<br />"); -> split and join, another way to do replace
- String.prototype.replaceAll = function(needle, replacement) {return this.split(needle).join(replacement||"");}; -> similar to #4, but added to String prototype
ssh or scp to EC2
ssh -i ~/key.pem ec2-user@ec2-54-241-11-23.us-west-1.compute.amazonaws.com
scp -i ~/key.pem file.txt ec2-user@ec2-54-241-11-23.us-west-1.compute.amazonaws.com:~/
netstat -an |find /i "listening"
netstat -na | grep 443 | grep 66.151.139
tcpdump port 443
More tcpdump commands:
dump to file for wireshark analysis
sudo tcpdump -w tcp.dump2 net 66.151
dump to console for grep
sudo tcpdump -i en0 host 66.151.139
scp -i ~/key.pem file.txt ec2-user@ec2-54-241-11-23.us-west-1.compute.amazonaws.com:~/
netstat -an |find /i "listening"
netstat -na | grep 443 | grep 66.151.139
tcpdump port 443
More tcpdump commands:
dump to file for wireshark analysis
sudo tcpdump -w tcp.dump2 net 66.151
dump to console for grep
sudo tcpdump -i en0 host 66.151.139
Thursday, September 5, 2013
QUOTA_EXCEEDED_ERR: DOM Exception 22
I met this error when set data to sessionStorage. It means the data exceeded the browser limit. Most browsers have 2.5M or 5M limit per domain. Many developers assume that one character equals one byte, but this is not a safe assumption. Strings in JavaScript are UTF-16, so each character requires two bytes of memory. This means that while many browsers have a 5 MB limit, you can only store 2.5 M characters.
http://dev.w3.org/html5/webstorage/#disk-space recommends a 5M limit, but as of writing, Chrome 29, Safari 6 still use 2.5M limit, Firefox/Opera are ok. Also Firefox/Opera allows user to adjust the default value (about:config - search quota), Chrome/Safari/IE do not allow.
The practice is to handle this error in Javascript, and fallback to browser memory.
The error might look like as below
Uncaught QuotaExceededError: An attempt was made to add something to storage that exceeded the quota.
http://dev.w3.org/html5/webstorage/#disk-space recommends a 5M limit, but as of writing, Chrome 29, Safari 6 still use 2.5M limit, Firefox/Opera are ok. Also Firefox/Opera allows user to adjust the default value (about:config - search quota), Chrome/Safari/IE do not allow.
The practice is to handle this error in Javascript, and fallback to browser memory.
The error might look like as below
Uncaught QuotaExceededError: An attempt was made to add something to storage that exceeded the quota.
Browser storage
There are the following storage types in browser side when do Javascript based web app.
- Cookie: there is # of cookies per domain limit, and size limit (around 4K limit)
- Memory: limit by system (?), data lost during browser refresh
- WebStorage: (sessionStorage, or localStorage) - http://diveintohtml5.info/storage.html
- AppCache: It is to store the whole web-app (pages, images, css, JavaScript) in the browser to make it available offline.
- Web SQL: relational database, SQLlite on browser, deprecated
- IndexedDB: NoSQL DB on browser side. IndexedDB which is already available on Chrome 12+ and Firefox 5+, and, soon, in IE 10 as well.
- GlobalStorage - deprecated
Tuesday, September 3, 2013
Cross Site Scripting (XSS)
Today Salesforce rejected our app due to several security issues. One of these was
Cross Site Scripting (XSS). This is a common issue in security domain, and we need employ the changes to prevent XSS. The problem, and possible fix solution from Salesforce is very clear, so I copied and pasted here for future reference.
Description:
The attack
involves reflecting user provided data into the browser, without any
modification at the server's end. Cross Site Scripting attacks can be scripted
in any browser scripting technology. There are 3 different types of Cross Site
Scripting attacks. The first, being the most simple, in which the data entered
is reflected back. The attack is temporary and is least risky. The second,
called Persistent Cross Site Scripting is very common on bulletin boards and
various social networking sites. The malicious input is stored on the server
and each time a user accesses the data, the code is interpreted. And finally,
the third form, called DOM based Cross Site Scripting, is perpetrated by exploiting
the accessibility of the DOM of HTML page the user is viewing, and then running
scripts with the user's privileges on his/her machine.
The developers of the application
need to have strong input validation in place. This can be done using either blacklists
or whitelists of characters. Similarly, the developers need to ensure that
output is well sanitized. This can be implemented by escaping all the content
being directed to the browser. Methods to boost cookie security should be
employed.
Recommendation:
Consider performing a combination
of input filtering and context-appropriate output encoding, such as HTML entity
encoding for all the data that could be provided by external data sources like
databases, users or web services if that data is included in the application’s
output. Sanitize all user input. Enforce input validation checks on the server
side. Include data type checks, data size and range checks. Check user input
against whitelist values, check against other data values for logical accuracy
and data integrity based on business rules.
An example of a blacklist would
be where any input that contains characters that are considered “invalid” for
web applications, such as “ < > & ‘ `;. Despite efforts to
authoritatively identify all such characters, some characters are likely to be
left out. A better way of validating input would be to define a list of allowed
characters, also referred to as a whitelist.
Sunday, September 1, 2013
Object in ES-5
ES5 adds more features to Object.
Object.preventExtensions(obj) makes it impossible to add properties to obj. You can still change and delete properties.
Object.isExtensible(obj) is to check whether obj is extensible.
Object.seal(obj) prevents extensions and makes all properties “unconfigurable”. The latter means that the attributes of properties can’t be changed, any more. Read-only properties stay read-only, enumerable properties stay enumerable, etc. But You can still change the property.
Object.isSealed(obj) is to check whether obj is sealed.
Object.getOwnPropertyDescriptor(obj, 'foo')
Object.defineProperty(obj, 'foo', { enumerable: false });
Object.freeze(obj) makes all properties non-writable and seals obj.
Object.isFrozen(obj) is to check whether obj is frozen.
Reference:
http://ejohn.org/blog/ecmascript-5-objects-and-properties/
http://kangax.github.io/es5-compat-table/
Object.preventExtensions(obj) makes it impossible to add properties to obj. You can still change and delete properties.
Object.isExtensible(obj) is to check whether obj is extensible.
Object.seal(obj) prevents extensions and makes all properties “unconfigurable”. The latter means that the attributes of properties can’t be changed, any more. Read-only properties stay read-only, enumerable properties stay enumerable, etc. But You can still change the property.
Object.isSealed(obj) is to check whether obj is sealed.
Object.getOwnPropertyDescriptor(obj, 'foo')
Object.defineProperty(obj, 'foo', { enumerable: false });
Object.freeze(obj) makes all properties non-writable and seals obj.
Object.isFrozen(obj) is to check whether obj is frozen.
Reference:
http://ejohn.org/blog/ecmascript-5-objects-and-properties/
http://kangax.github.io/es5-compat-table/
Subscribe to:
Posts (Atom)