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