import sys
sys.path.append('lib')
import re
import cgi
import urllib
import simplejson
from google.appengine.ext import webapp
from google.appengine.ext import db
from math import floor
from time import time
# Signature validation required libraries import
import base64
import hashlib
import oauth
from Crypto.PublicKey import RSA
from Crypto.Util import number
# Local port; change if another process is running on 8080
PORT = '8080'
class User(db.Model):
personId = db.StringProperty()
container = db.StringProperty()
class Photo(db.Model):
name = db.StringProperty()
content = db.BlobProperty()
contentType = db.StringProperty()
user = db.ReferenceProperty(User)
tags = db.StringListProperty()
class RootHandler(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
self.response.out.write('')
self.response.out.write('
')
self.response.out.write(''.join(['Upload photo']))
self.response.out.write('
')
self.response.out.write(''.join(['Fetch user photos']))
self.response.out.write('
')
self.response.out.write(''.join(['Fetch group photos']))
self.response.out.write('
')
self.response.out.write(''.join(['Fetch user tags']))
self.response.out.write('
')
self.response.out.write(''.join(['Add photo tag']))
self.response.out.write('')
self.response.out.write('')
class TagsHandler(webapp.RequestHandler):
def get(self):
if not _isValidSignature(self):
self.response.out.write('SIGNATURE INVALID')
return
personId = self.request.get('opensocial_owner_id')
container = self.request.get('oauth_consumer_key')
tags = getTagsForUser(container, personId)
self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
self.response.out.write(simplejson.dumps({'tags': list(set(tags))}))
class PhotosHandler(webapp.RequestHandler):
def get(self):
if not _isValidSignature(self):
self.response.out.write('SIGNATURE INVALID')
return
personId = self.request.get('opensocial_owner_id')
container = self.request.get('oauth_consumer_key')
photos = getPhotos(container, personId)
self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
self.response.out.write(simplejson.dumps({'resultsSet': photos}))
def post(self):
form = cgi.FieldStorage()
peopleIds = urllib.unquote(form.getfirst('people')).split(',')
if not _isValidSignature(self):
self.response.out.write('SIGNATURE INVALID')
return
personId = self.request.get('opensocial_owner_id')
container = self.request.get('oauth_consumer_key')
photoSetCollection = []
for id in peopleIds:
photoSet = {}
photoSet['name'] = id
photoSet['photos'] = getPhotos(container, id)
if len(photoSet['photos']) > 0:
photoSetCollection.append(photoSet)
self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
self.response.out.write(simplejson.dumps({'resultsCollection': photoSetCollection}))
class PhotoHandler(webapp.RequestHandler):
def get(self):
match = re.search(r'^http://.*/photo/([\w\.]*?):([\w\.]*?):([\w\.]*)', urllib.unquote(self.request.uri))
if match:
photo = getPhoto(match.group(1), match.group(2), match.group(3))
if photo:
self.response.headers['Content-Type'] = str(photo.contentType)
self.response.out.write(photo.content)
def post(self):
form = cgi.FieldStorage()
if not form.has_key('file'):
if not _isValidSignature(self):
self.response.out.write('SIGNATURE INVALID')
return
personId = self.request.get('opensocial_owner_id')
container = self.request.get('oauth_consumer_key')
if form.getfirst('text'):
textTag = urllib.unquote(form.getfirst('text'))
match = re.search(r'^http://.*/photo/([\w\.]*?):([\w\.]*?):([\w\.]*)', urllib.unquote(self.request.uri))
if match:
photo = getPhoto(match.group(1), match.group(2), match.group(3))
if photo:
self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
if 'textTag' in locals():
addTextTagToPhoto(photo, textTag)
self.response.out.write('Text tag added successfully')
else:
fileItem = form['file']
personId = form.getfirst('personId')
container = form.getfirst('container')
self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
photo = createPhoto(container, personId, fileItem)
if photo:
self.response.out.write('Photo added.
')
self.response.out.write(''.join(['
']))
def getUser(container, personId):
user = User.get_or_insert(''.join([container, personId]), container=container, personId=personId)
return user
def getPhoto(container, personId, photoName):
key = ''.join([container, personId, '_', photoName])
return Photo.get_by_key_name(key)
def getPhotos(container, personId):
retArray = []
photos = getPhotosForUser(container, personId)
if photos:
for objt in photos:
photo = {}
photo['url'] = ''.join(['http://localhost:', PORT, '/photo/', container, ':', personId, ':', objt.name])
photo['tags'] = objt.tags
retArray.append(photo)
return retArray
def getPhotosForUser(container, personId):
user = getUser(container, personId)
return db.GqlQuery("SELECT * FROM Photo WHERE user = :1", user)
def getTagsForUser(container, personId):
tags = []
photos = getPhotosForUser(container, personId)
if photos:
for objt in photos:
for tag in objt.tags:
tags.append(tag)
return tags
def addTextTagToPhoto(photo, textTag):
photo.tags.append(textTag)
photo.put()
def createPhoto(container, personId, fileItem):
user = getUser(container, personId)
name = ''.join([str(int(floor(time()))), fileItem.filename])
key = ''.join([container, personId, '_', name])
photo = Photo(key_name=key)
photo.user = user
photo.name = name
photo.content = db.Blob(fileItem.file.read())
photo.contentType = fileItem.type
photo.put()
return photo
def _isValidSignature(self):
# Code lab hack:
# If the container is 'appengine' (e.g. app is running on localhost), return True
if self.request.get('oauth_consumer_key') == 'appengine':
return True
# Construct a RSA.pubkey object
exponent = 65537
public_key_str = """0x\
00b1e057678343866db89d7dec2518\
99261bf2f5e0d95f5d868f81d600c9\
a101c9e6da20606290228308551ed3\
acf9921421dcd01ef1de35dd3275cd\
4983c7be0be325ce8dfc3af6860f7a\
b0bf32742cd9fb2fcd1cd1756bbc40\
0b743f73acefb45d26694caf4f26b9\
765b9f65665245524de957e8c547c3\
58781fdfb68ec056d1"""
public_key_long = long(public_key_str, 16)
public_key = RSA.construct((public_key_long, exponent))
# Rebuild the message hash locally
oauth_request = oauth.OAuthRequest(http_method=self.request.method,
http_url=self.request.url,
parameters=self.request.params.mixed())
message = '&'.join((oauth.escape(oauth_request.get_normalized_http_method()),
oauth.escape(oauth_request.get_normalized_http_url()),
oauth.escape(oauth_request.get_normalized_parameters()),))
local_hash = hashlib.sha1(message).digest()
# Apply the public key to the signature from the remote host
sig = base64.decodestring(urllib.unquote(self.request.params.mixed()["oauth_signature"]))
remote_hash = public_key.encrypt(sig, '')[0][-20:]
# Verify that the locally-built value matches the value from the remote server.
if local_hash==remote_hash:
return True
else:
return False