fredag den 9. marts 2012

Did you remember to CORS enable your API?

One of the great things about API’s that return JSON is that you can use them directly from the browser. This means you can serve an entirely static page, and still show interesting dynamic data. But for security reasons browsers only allows you to send Ajax requests to the domain you loaded the page from. This serverely restricts the possibilites of using third party API’s directly from the browser.

Fortunately there exists ways to circumvent this restriction. The most popular is JSONP (JSON with padding). I won’t go into JSONP in this post, but suffice it to say that because the method is based on inserting a script tag in the page, it only works for GET requests.

Enter CORS (Cross-Origin Resource Sharing)…

CORS is a method for the server to tell the browser that it is safe to do cross origin requests to this endpoint. It works by simply adding the header Access-Control-Allow-Origin to the response. Set it to * (wildcard) to allow all domains. At resmio we have CORS enabled for our API. You can see it in action by doing

curl -I -k https://resmio.com/api/v1

This allows us to quickly throw up a new site with no server side code, that consumes our public API. Incidentally we’ve built a JavaScript library that makes it easy to access our API, that we can reuse on all sites.

When is it safe to use CORS?

You should only allow CORS for stuff that does not use session cookies, otherwise you’d be susceptible to Cross-site request forgery attacks.

Browser support?

CORS is supported by all modern browsers. One caveat is that in Internet Explorer, CORS is not supported by the regular Ajax request object. Instead you have to use an XDomainRequest object. If you use jQuery you can include the ajaxTransport xdr.js for IE support.

Thus, if you already have an API you can make it easy to use for everybody by just adding one header to your responses.

Posted via email from I used to be a young man...

tirsdag den 6. marts 2012

Django SMS, a simple Django app for sending SMS's.

Today I uploaded Django SMS to pypi. It is a simple Django app for sending SMS's. It supports interchangable backends. The reason you might need this, is that you'd want different things to happen depending on whether you are developing your application, running tests or running your code in production.

  • During developement you probably want to output SMS's to the console so you can see what is going on. Django SMS ships with a console backend.
  • When running your test suite you want your tests to be able to check the content of your SMS's. Django SMS ships with a local memory backend.
  • When running in production you want SMS's to actually be sent through your chosen gateway. Django SMS defines a simple interface that allows you to implement backends supporting the gateway you'd like to use.

Using Django SMS is as simple as calling the toplevel function send_sms with the sender, receiver and message. Give it a try or fork it on bitbucket

Posted via email from I used to be a young man...

lørdag den 25. december 2010

How to (safely) embed JSON in a script tag

If you embed JSON in a web page, you must make sure you are not vulnerable to XSS (Cross-site scripting) attacks. Usually you would just HTML escape your content, but that corrupts your JSON.

instead escape the script start and end characters and the ampersand character with their unicode encodings. This will prevent XSS but still allow for valid JSON

json += json.replace('&', '\\u0026') json += json.replace('<', '\\u003c') json += json.replace('>', '\\u003e')

If you use simplejson for generating JSON, the newest version has a JSONEncoderForHTML that does exactly this.

 

Posted via email from Yet another blog...

lørdag den 7. november 2009

Migrating trac from SQLite to MySQL

A little while ago I was tasked with migrating about hundred trac instances from SQLite to MySQL. Unfortunately SQLites schema definitions is not compatible with MySQL. So I had to wrote some scripts to handle it. After a little bit of experimenting everything worked perfectly.

The Strategy I employed was like this:

  1. Make a dump of a default MySQL trac db schema.
  2. Make a dump of the trac SQLite database
  3. Remove db schema definitions from the SQLite dump
  4. Concatenate the MySQL and SQLite dumps
  5. Load data into MySQL
  6. Edit Trac's database settings to use MySQL
  7. Do a trac-admin upgrade

MYSQL_USER=username
MYSQL_PSWD=password

SQLITECMD=sqlite3
TRACBASE=/path/to/tracreps

# loop through all trac instances in tracreps
for d in $( ls $TRACBASE )
do
if [ -d "$TRACBASE/$d" ]; then
echo $d
TRACNAME=$d

# create database in mysql
echo "creating database for $TRACNAME..."
mysqladmin --user $MYSQL_USER -p$MYSQL_PSWD create $TRACNAME

# dump sqlite db structure + data
echo "dumping data from sqlite..."
$SQLITECMD $TRACBASE/$TRACNAME/db/trac.db .dump > trac.sqlite.sql

# remove database definitions from dump using a custom python script
echo "cleaning database definition from dump..."
`./cleansql.py < trac.sqlite.sql > trac.sqlite.sql.dataonly`

# concatenate mysql database definitions and sqlite data
cat trac.mysql.sql trac.sqlite.sql.dataonly > trac.sql

echo "loading data into mysql..."
mysql --user $MYSQL_USER -p$MYSQL_PSWD --default_character_set utf8 $TRACNAME < trac.sql

# edit database connection string in trac.ini
sed -i "s?sqlite:db/trac.db?mysql://$MYSQL_USER:$MYSQL_PSWD@localhost:3306/$TRACNAME?" $TRACBASE/$TRACNAME/conf/trac.ini

echo "upgrading mysql database..."
trac-admin $TRACBASE/$TRACNAME upgrade --no-backup

 

To remove schema definitions from the sqlite dump and fix some incompatibilities I made this python script referenced above as cleansql.py:

#!/usr/bin/env python

import sys
import re

file = sys.stdin.read()
file = re.sub(r'(CREATE (TABLE|INDEX)[^;]*|COMMIT|BEGIN TRANSACTION);', '', file)
file = re.sub(r'INSERT INTO "([^"]+)"', lambda m: 'INSERT INTO `%s`' % m.groups(1), file)
# fix sql for reports
file = re.sub(r'CAST\((.+) AS int\)', lambda m: 'CAST(%s AS signed)' % m.groups(1), file)

sys.stdout.write(file)

And that's it. I hope this will benefit someone tasked with the same job.

 

Posted via web from Yet another blog...

mandag den 1. december 2008