def login(self,env,start_response): cl = vanilla.getContentLength(env) if cl == None: return vanilla.http_error(411,env,start_response,'missing Content-Length header') content = env['wsgi.input'].read(cl) query = urlparse.parse_qs(content) if 'username' not in query: return vanilla.http_error(400,env,start_response,msg='missing username') #Use first occurence from query string username = query['username'][0] if 'password' not in query: return vanilla.http_error(400,env,start_response,msg='missing password') #Use first occurence from query string password = query['password'][0] userId = self.authenticateUser(username,password) if userId == None: self.logger.info('Failed authorization for user:%s' , username) return vanilla.sendJsonWsgiResponse(env,start_response,{'error':'bad username or password'}) session = self.sm.startSession(username,userId) return vanilla.sendJsonWsgiResponse(env,start_response,self.getResponseForSession(session),additionalHeaders=[session.getCookie()])
def __call__(self, env, start_response): #Extract and normalize the path #Posix path may not be the best approach here but #no alternate has been found pathInfo = posixpath.normpath(env['PATH_INFO']) #Split the path into components. Drop the first #since it should always be the empty string pathComponents = pathInfo.split('/')[1 + self.pathDepth:] env['fairywren.pathComponents'] = pathComponents requestMethod = env['REQUEST_METHOD'] #The default is request not found errorCode = 404 #Find a resource with a patch matching the requested one for resource in self.resources: kwargs = resource.wants(pathComponents) if kwargs == None: continue #If the method does not agree with the resource, the #code is method not supported if requestMethod != resource.method: errorCode = 405 continue self.logger.debug('%s:%s handled by %s', requestMethod, pathInfo, resource.getName()) if resource.requireAuthentication: session = self.sm.getSession(env) if session == None: return vanilla.sendJsonWsgiResponse( env, start_response, restInterface.NOT_AUTHENTICATED) #Check to see if the resource requires authorization if resource.requireAuthorization: authorized = resource.allowSelf and resource.getOwnerId( *pathComponents) == session.getId() authorized |= self.authorizeUser(session, resource.allowedRoles) if not authorized: self.logger.debug('%s:%s not authorized for %s', requestMethod, pathInfo, session.getUsername()) return vanilla.sendJsonWsgiResponse( env, start_response, restInterface.NOT_AUTHORIZED) return resource(env, start_response, session, **kwargs) else: return resource(env, start_response, **kwargs) self.logger.info('%s:%s not handled, %d', requestMethod, pathInfo, errorCode) return vanilla.http_error(errorCode, env, start_response)
def __call__(self,env,start_response): #Extract and normalize the path #Posix path may not be the best approach here but #no alternate has been found pathInfo = posixpath.normpath(env['PATH_INFO']) #Split the path into components. Drop the first #since it should always be the empty string pathComponents = pathInfo.split('/')[1+self.pathDepth:] env['fairywren.pathComponents'] = pathComponents requestMethod = env['REQUEST_METHOD'] #The default is request not found errorCode = 404 #Find a resource with a patch matching the requested one for resource in self.resources: kwargs = resource.wants(pathComponents) if kwargs == None: continue #If the method does not agree with the resource, the #code is method not supported if requestMethod != resource.method: errorCode = 405 continue self.logger.debug('%s:%s handled by %s',requestMethod,pathInfo,resource.getName()) if resource.requireAuthentication: session = self.sm.getSession(env) if session == None: return vanilla.sendJsonWsgiResponse(env,start_response,restInterface.NOT_AUTHENTICATED) #Check to see if the resource requires authorization if resource.requireAuthorization: authorized = resource.allowSelf and resource.getOwnerId(*pathComponents)==session.getId() authorized |= self.authorizeUser(session,resource.allowedRoles) if not authorized: self.logger.debug('%s:%s not authorized for %s',requestMethod,pathInfo,session.getUsername()) return vanilla.sendJsonWsgiResponse(env,start_response,restInterface.NOT_AUTHORIZED) return resource(env,start_response,session,**kwargs) else: return resource(env,start_response,**kwargs) self.logger.info('%s:%s not handled, %d', requestMethod,pathInfo,errorCode) return vanilla.http_error(errorCode,env,start_response)
def listInvites(self,env,start_response,session,uid): uid = int(uid,16) #Potential pitfall in this implementation: #If a user is authorized to perform a GET on this resource but #user for the uid does not exist, this stil returns an empty list response = { 'invites' : list(self.users.listInvitesByUser(uid)) } return vanilla.sendJsonWsgiResponse(env,start_response,response)
def changeRolesOfUser(self,env,start_response,session,uid,roles): uid = int(uid,16) try: self.users.setUserRoles(roles,uid) except ValueError as e: return vanilla.http_error(400,env,start_response,msg=e.message) return vanilla.sendJsonWsgiResponse(env,start_response,{'roles':self.users.getUserRoles(uid)})
def changePassword(self,env,start_response,session,uid,password): uid = int(uid,16) if None == self.authmgr.changePassword(uid,password): return vanilla.http_error(400,env,start_response) return vanilla.sendJsonWsgiResponse(env,start_response,{})
def inviteStatus(self,env,start_response,secret): secret = base64.urlsafe_b64decode(secret + '=') try: claimed =self.users.getInviteState(secret) except ValueError as e: return vanilla.http_error(404,env,start_response,msg=e.message) return vanilla.sendJsonWsgiResponse(env,start_response,{'claimed':claimed})
def showSession(self, env, start_response, session): response = self.getResponseForSession(session) return vanilla.sendJsonWsgiResponse( env, start_response, response, additionalHeaders=[session.getCookie()])
def getSwarm(self,env,start_response,session): response = self.swarm.getPeers() for peer in response.itervalues(): for d in peer: d.pop('peerId') return vanilla.sendJsonWsgiResponse(env,start_response,response)
def addUser(self,env,start_response,session,password,username): try: resourceForNewUser,_ = self.users.addUser(username,password) except users.UserAlreadyExists: return vanilla.http_error(409,env,start_response,'user already exists') response = { 'href' : resourceForNewUser } return vanilla.sendJsonWsgiResponse(env,start_response,response)
def updateTorrent(self,env,start_response,session,uid,extended,title): uid = int(uid,16) try: self.torrents.updateTorrent(uid,title,extended) except ValueError as e: return vanilla.http_error(404,env,start_response,msg=e.message) return vanilla.sendJsonWsgiResponse(env,start_response,{})
def deleteTorrent(self,env,start_response,session,uid): uid = int(uid,16) try: torrent = self.torrents.deleteTorrent(uid) except ValueError as e: return vanilla.http_error(404,env,start_response,msg=e.message) return vanilla.sendJsonWsgiResponse(env,start_response,{})
def claimInvite(self,env,start_response,secret,username,password): secret = base64.urlsafe_b64decode(secret + '=') try: newuser = self.users.claimInvite(secret,username,password) except users.UserAlreadyExists: return vanilla.http_error(409,env,start_response,msg='User with that name already exists') except ValueError as e: return vanilla.http_error(404,env,start_response,msg=e.message) return vanilla.sendJsonWsgiResponse(env,start_response,{'href' : newuser})
def userInfo(self,env,start_response,session,uid): uid = int(uid,16) response = self.users.getInfo(uid) if response == None: return vanilla.http_error(404,env,start_response) if session.getId() == uid: response['announce'] = { 'href': self.torrents.getAnnounceUrlForUser(uid) } return vanilla.sendJsonWsgiResponse(env,start_response,response)
def torrentInfo(self,env,start_response,session,uid): uid = int(uid,16) response = self.torrents.getInfo(uid) if response == None: return vanilla.http_error(404,env,start_response,msg='no such torrent') torrentInfoHash = response.pop('infoHash') numSeeds,numLeeches = self.peers.getNumberOfPeers(torrentInfoHash) response['extended'] = self.torrents.getExtendedInfo(uid) response['seeds'] = numSeeds response['leeches'] = numLeeches return vanilla.sendJsonWsgiResponse(env,start_response,response)
def login(self, env, start_response): cl = vanilla.getContentLength(env) if cl == None: return vanilla.http_error(411, env, start_response, 'missing Content-Length header') content = env['wsgi.input'].read(cl) query = urlparse.parse_qs(content) if 'username' not in query: return vanilla.http_error(400, env, start_response, msg='missing username') #Use first occurence from query string username = query['username'][0] if 'password' not in query: return vanilla.http_error(400, env, start_response, msg='missing password') #Use first occurence from query string password = query['password'][0] userId = self.authenticateUser(username, password) if userId == None: self.logger.info('Failed authorization for user:%s', username) return vanilla.sendJsonWsgiResponse( env, start_response, {'error': 'bad username or password'}) session = self.sm.startSession(username, userId) return vanilla.sendJsonWsgiResponse( env, start_response, self.getResponseForSession(session), additionalHeaders=[session.getCookie()])
def searchTorrents(self,env,start_response,session,query): tokens = query.get('token') if tokens == None: return vanilla.http_error(400,env,start_response,'search must have at least one instance of token parameter') if len(tokens) > 5: return vanilla.http_error(400,env,start_response,'search may not have more than 5 tokens') listOfTorrents = [] for torrent in self.torrents.searchTorrents(tokens): torrentInfoHash = torrent.pop('infoHash') torrent.pop('id') seeds, leeches = self.peers.getNumberOfPeers(torrentInfoHash) torrent['seeds'] = seeds torrent['leeches'] = leeches listOfTorrents.append(torrent) return vanilla.sendJsonWsgiResponse(env,start_response, {'torrents': listOfTorrents})
def createTorrent(self,env,start_response,session): if not 'CONTENT_TYPE' in env: return vanilla.http_error(411,env,start_response,'missing Content-Type header') contentType = env['CONTENT_TYPE'] if 'multipart/form-data' not in contentType: return vanilla.http_error(415,env,start_response,'must be form upload') forms,files = multipart.parse_form_data(env) if 'torrent' not in files or 'title' not in forms: return vanilla.http_error(400,env,start_response,'missing torrent or title') try: extended = json.loads(forms.get('extended','{}')) except ValueError: return vanilla.http_error(400,env,start_response,'bad extended info') if not isinstance(extended,dict): return vanilla.http_error(400,env,start_response,'extended info must be dict') data = files['torrent'].raw try: newTorrent = torrents.Torrent.fromBencodedData(data) except ValueError as e: return vanilla.http_error(400,env,start_response,str(e)) response = {} response['redownload'] = newTorrent.scrub() response['redownload'] |= self.torrents.getAnnounceUrlForUser(session.getId())!=newTorrent.getAnnounceUrl() try: url,infoUrl = self.torrents.addTorrent(newTorrent,forms['title'],session.getId(),extended) except ValueError as e: #Thrown when a torrent already exists with this info hash return vanilla.http_error(400,env,start_response,e.message) response['metainfo'] = { 'href' : url } response['info'] = { 'href' : infoUrl } return vanilla.sendJsonWsgiResponse(env,start_response,response)
def listTorrents(self,env,start_response,session): if 'QUERY_STRING' not in env: query = {} else: query = urlparse.parse_qs(env['QUERY_STRING']) if 'search' in query: return self.searchTorrents(env,start_response,session,query) #Use the first occurence of the supplied parameter #With a default resultSize = query.get('resultSize',[self.MAX_TORRENTS_PER_RESULT])[0] try: resultSize = int(resultSize) except ValueError: return vanilla.http_error(400,env,start_response,'resultSize must be integer') #Use the first occurence of the supplied parameter #With a default of zero subset = query.get('subset',[0])[0] try: subset = int(subset) except ValueError: return vanilla.http_error(400,env,start_response,'subset must be integer') listOfTorrents = [] for torrent in self.torrents.getTorrents(resultSize,subset): torrent.pop('id') torrentInfoHash = torrent.pop('infoHash') seeds, leeches = self.peers.getNumberOfPeers(torrentInfoHash) torrent['seeds'] = seeds torrent['leeches'] = leeches listOfTorrents.append(torrent) return vanilla.sendJsonWsgiResponse(env,start_response, {'torrents' : listOfTorrents ,'numSubsets' : int(math.ceil(self.torrents.getNumTorrents() / float(resultSize)))} )
def showSession(self,env,start_response,session): response = self.getResponseForSession(session) return vanilla.sendJsonWsgiResponse(env,start_response,response,additionalHeaders=[session.getCookie()])
def listRoles(self,env,start_response,session): return vanilla.sendJsonWsgiResponse(env,start_response,{'roles':self.getRoles()})
def listRolesOfUser(self,env,start_response,session,uid): uid = int(uid,16) #Potential pitfall in this implementation: #If the user for the uid does not exist, this stil returns an empty list return vanilla.sendJsonWsgiResponse(env,start_response,{'roles':self.users.getUserRoles(uid)})
def createInvite(self,env,start_response,session): pathOfNewInvite = self.users.createInvite(session.getId()) return vanilla.sendJsonWsgiResponse(env,start_response,{'href':pathOfNewInvite})