def test_new_hacked(self): class Sec6: pass cerealizer.register(Sec6) o = Sec6() Sec6.__new__ = lambda Class: self.fail() cerealizer.loads(cerealizer.dumps(o))
def test_setstate_hacked(self): class Sec4: pass cerealizer.register(Sec4) o = Sec4() Sec4.__setstate__ = lambda obj, state: self.fail() cerealizer.loads(cerealizer.dumps(o))
def test_getstate_hacked(self): class Sec5: pass cerealizer.register(Sec5) o = Sec5() Sec5.__getstate__ = lambda obj: self.fail() cerealizer.loads(cerealizer.dumps(o))
def __init__(self, infoFileName): self.songName = os.path.basename(os.path.dirname(infoFileName)) self.fileName = infoFileName self.info = ConfigParser() self._difficulties = None try: self.info.read(infoFileName) except: pass # Read highscores and verify their hashes. # There ain't no security like security throught obscurity :) self.highScores = {} scores = self._get("scores", str, "") if scores: scores = cerealizer.loads(binascii.unhexlify(scores)) for difficulty in scores.keys(): try: difficulty = difficulties[difficulty] except KeyError: continue for score, stars, name, hash in scores[difficulty.id]: if self.getScoreHash(difficulty, score, stars, name) == hash: self.addHighscore(difficulty, score, stars, name) else: Log.warn("Weak hack attempt detected. Better luck next time.")
def poll(self): while 1: readable_socks, writeable_socks, dropit = select.select(self.socks, self.socks_writing, [], 0.0) for sock in readable_socks: if sock is self.udp: data = self.udp.recv(65000) code = data[0] self.nb_byte += len(data) + 8 # 8 is for UDP header if code == CODE_STATE: self.nb_state += 1 #import random #if random.random() < 0.2: continue self.udp.send(CODE_ACK_STATE + data[1:13]) level = Unique.undumpsuid(data[1:3]) round = struct.unpack("!Q", data[3:11])[0] if level and level.queued_state_round < round: level.queued_state = data[11:] level.queued_state_round = round else: raise NetworkError("Unknown code '%s'!" % code) elif sock is self.tcp: data = sock.read() if not data: if sock.closed: raise NetworkError("Connexion to server closed!") continue self.nb_byte += 4 + len(data) + 8 print "DATA", len(data), "'%s'" % data[0] code = data[0] if code == CODE_MESSAGE: obj = Unique.undumpsuid(data[1:3]) obj.do_message(data[3:]) elif code == CODE_OBJ: obj = cerealizer.loads(data[1:]) obj.loaded() # This calls level.add_mobile if needed if isinstance(obj, Mobile): print "* Tofu * %s received in level %s." % (obj, obj.level) elif isinstance(obj, Level ): print "* Tofu * %s received with %s." % (obj, ", ".join([repr(mobile) for mobile in obj.mobiles])) else: print "* Tofu * %s received." % obj elif code == CODE_REMOVE_MOBILE: mobile = Unique.undumpsuid(data[1:3]) print "* Tofu * %s removed from %s." % (mobile, mobile.level) mobile.level.remove_mobile(mobile) mobile.discard() elif code == CODE_OWN_CONTROL: mobile = Unique.undumpsuid(data[1:3]) mobile.control_owned()
def load(self, filename): #load savegame data datafileobj = open(filename, "rb") data = datafileobj.read()#read in save data datafileobj.close() data = zlib.decompress(data) #decompress it data = cerealizer.loads(data) self.obj_props = data[0] #get object properties self.game_props = data[1] #and game properties
def test_cycle2(self): class Obj11(object): pass cerealizer.register(Obj11) o = Obj11() o.o = o o2 = cerealizer.loads(cerealizer.dumps(o)) assert o2.o is o2
def test_cycle2(self): class ObjEmpty(object): pass cerealizer.register(ObjEmpty) o = ObjEmpty() o.o = o o2 = cerealizer.loads(cerealizer.dumps(o)) assert o2.o is o2
def test_cycle3(self): class Parent: pass class Child: def __init__(self, parent): self.parent = parent def __getstate__(self): return (self.parent,) def __setstate__(self, state): self.parent = state[0] cerealizer.register(Parent) cerealizer.register(Child) p = Parent() p.c = Child(p) p2 = cerealizer.loads(cerealizer.dumps(p)) assert not p2.c.parent is None
def testHash(self): # For the record, the worldchart used to reject the following 3 hashes... # (name strings are UTF8 encoded) scoresHash = "63657265616c310a330a646963740a6c6973740a7475706c650a340a"\ "6936333834360a69350a7531310a50617363616c4769617264733430"\ "0a343839666538656632343239646564373637363835373930303936"\ "31323531633136303662373863310a72310a69310a310a72320a72300a" scores = cerealizer.loads(binascii.unhexlify(scoresHash)) #print scores[1][0][2] self.assertEqual(scores[1][0][2], "PascalGiard") #scoreExtHash = "63657265616c310a330a646963740a6c6973740a7475706c650a"\ # "390a7334300a3438396665386566323432396465643736373638"\ # "353739303039363132353163313630366237386369350a693236"\ # "310a693237300a6937320a7331310a466f4669582d332e313030"\ # "69300a73300a6936333834360a310a72310a69310a310a72320a"\ # "72300a" #songHash = "6551c0f99efddfd3c5c7ef2d407c81b8e3001a43" # Worldchart accepts this one (name string is NOT UTF8 encoded) scoresHash = "63657265616c310a330a646963740a6c6973740a7475706c650a340a"\ "693234323032320a69350a73350a417a7a636f7334300a3233336431"\ "37373139653539323066366461373034633432343864646632313930"\ "32323939656438310a72310a69300a310a72320a72300a" scores = cerealizer.loads(binascii.unhexlify(scoresHash)) self.assertEqual(scores[0][0][2], "Azzco") #print scores[0][0] # Shows that name string IS NOT UTF8 encoded # Worldchart used to reject this one (name string is UTF8 encoded) scoresHash = "63657265616c310a330a646963740a6c6973740a7475706c650a340a"\ "693135313632390a69340a75350a417a7a636f7334300a3661306562"\ "35346438343962613065376464363836396430373966386631316366"\ "61333133633264310a72310a69300a310a72320a72300a" scores = cerealizer.loads(binascii.unhexlify(scoresHash)) self.assertEqual(scores[0][0][2], "Azzco") print scores[0][0] # Shows that name string IS UTF8 encoded print scores[0][0][2] score = scores[0][0][0], scores[0][0][1], str(scores[0][0][2]), scores[0][0][3] print score
def test_cycle3(self): class Parent: pass class Child: def __init__(self, parent): self.parent = parent def __getstate__(self): return (self.parent,) def __setstate__(self, state): self.parent = state[0] cerealizer.register(Parent) cerealizer.register(Child) p = Parent() p.c = Child(p) p2 = cerealizer.loads(cerealizer.dumps(p)) assert p2.c.parent is not None
def test_alias1(self): class OldObj(object): def __init__(self): self.x = 1 self.name = "jiba" cerealizer.register(OldObj) o = OldObj() s = cerealizer.dumps(o) reload(cerealizer) class NewObj(object): def __init__(self): self.x = 2 self.name = "jiba2" cerealizer.register(NewObj) cerealizer.register_alias(NewObj, "__main__.OldObj") o = cerealizer.loads(s) assert o.__class__ is NewObj assert o.x == 1 assert o.name == "jiba"
def test_alias(self): class OldObj(object): def __init__(self): self.x = 1 self.name = "jiba" cerealizer.register(OldObj) o = OldObj() s = cerealizer.dumps(o) imp.reload(cerealizer) class NewObj(object): def __init__(self): self.x = 2 self.name = "jiba2" cerealizer.register(NewObj) cerealizer.register_alias(NewObj, "__main__.OldObj") o = cerealizer.loads(s) assert o.__class__ is NewObj assert o.x == 1 assert o.name == "jiba"
def MediaInfoLookup(url): """ Returns the media info stored in the recently browsed item list for the given provider URL or None if the item isn't found in the recently browsed item list. """ # Get clean copy of URL user has played. decoded_url = String.Decode(str(url)) #Log(decoded_url) # See if the URL being played is on our recently browsed list. item = cerealizer.loads(Data.Load(BROWSED_ITEMS_KEY)).getByURL(decoded_url) if (item is None): Log("****** ERROR: Watching Item which hasn't been browsed to") return "" # Return the media info that was stored in the recently browsed item. return demjson.encode(item[0])
def loads(s): return cerealizer.loads(base64.decodestring(s))
def test_craked_file1(self): craked_file = "cereal1\n2\n__builtin__.dict\nfile\n0\nr0\nr1\n" #self.assertRaises(StandardError, lambda: cerealizer.loads(craked_file)) self.assertRaises(Exception, lambda: cerealizer.loads(craked_file))
def test_cycle1(self): obj1 = [1, [2.2, "jiba"]] obj1[1].append(obj1) obj2 = cerealizer.loads(cerealizer.dumps(obj1)) assert repr(obj1) == repr(obj2) # Cannot use == on cyclic list!
def loads_dumps_and_compare(self, obj1): obj2 = cerealizer.loads(cerealizer.dumps(obj1)) assert obj1 == obj2
def test_identity(self): o = {} l1 = [o, o] l2 = cerealizer.loads(cerealizer.dumps(l1)) assert l2[0] is l2[1]
def loads(objstr): """ De-serialize the given string into it's original form. """ obj = cerealizer.loads(objstr) return obj
def unpack(string): unquoted_string = urllib.unquote(string) decoded_string = safe_decode(unquoted_string) return cerealizer.loads(decoded_string)
def test_craked_file1(self): craked_file = "cereal1\n2\n__builtin__.dict\nfile\n0\nr0\nr1\n" self.assertRaises(StandardError, lambda : cerealizer.loads(craked_file))
def testIntegrity(self): expected = self.scores scoresSerial = binascii.hexlify(cerealizer.dumps(self.scores)) result = cerealizer.loads(binascii.unhexlify(scoresSerial)) self.assertEqual(result, expected)
def deserialize(in_string): try: return pickle.loads(in_string) except EOFError: fail_message = Message(FAILURE,FAILURE) return fail_message
cerealizer.freeze_configuration() l = [] for i in range(20000): o = O() if l: o.o = l[-1] l.append(o) print("cerealizer") t = time.time() s = cerealizer.dumps(l) print("dumps in", time.time() - t, "s,", len(s), "bytes length") t = time.time() l2 = cerealizer.loads(s) print("loads in", time.time() - t, "s") import pickle print() print("pickle") t = time.time() s = pickle.dumps(l) print("dumps in", time.time() - t, "s,", len(s), "bytes length") t = time.time() l2 = pickle.loads(s) print("loads in", time.time() - t, "s")
def add_score(request): """ Add a score for a player and a song Returns a binary HttpResponse. """ # scores_to_insert = list() # get GET params song_title = escape(request.GET.get('songName', None)) song_hash = escape(request.GET.get('songHash', None)) song_instrument = escape(request.GET.get('songPart', None)) scores = escape(request.GET.get('scores', None)) version = escape(request.GET.get('version', None)) timestamp = escape(request.GET.get("timestamp", timezone.now())) remote_addr = request.META.get("REMOTE_ADDR", None) # check params if song_title is None or scores is None: return HttpResponse(False) # decode scores try: scores_decoded = cerealizer.loads(binascii.unhexlify(scores)) except ValueError: return HttpResponse(False) # log the event logger.info(f"New scores for the game version {version} at {remote_addr} for the song '{song_title}'", version, remote_addr, song_title) # find the song or create it song, created_song = Song.objects.get_or_create( defaults={'title': song_title}, title__iexact=song_title, ) if not song.notes: song.notes = song_hash song.save() # multiple Songs with the same title if song.notes != song_hash: now_iso = datetime.now().isoformat() new_song_title = song_title + ' ' + now_iso song = Song.objects.create(title=new_song_title, notes=song_hash) logger.info(f"Duplicate the song '{song_title}'", song_title) # get scores items for difficulty_id, scores_items in scores_decoded.items(): for score, stars, name, hash_score in scores_items: # check the hash hash_str = "%d%d%d%s" % (difficulty_id, score, stars, name) hash_bytes = bytes(hash_str, 'utf-8') hash_sha = hashlib.sha1(hash_bytes).hexdigest() if hash_score != hash_sha: continue # check stars number if stars < 0 or stars > Score.MAX_STARS: continue # check the difficulty if difficulty_id < 0 or difficulty_id >= len(Score.DIFFICULTIES): continue difficulty = Score.DIFFICULTIES[difficulty_id][0] # add scores to the list logger.info(f"Insert: score {score}, stars {stars}, difficulty {difficulty}, song '{name}'", score, stars, difficulty, name) # scores_to_insert.append((difficulty, score, stars, name)) # find the player or create it player, created_player = Player.objects.get_or_create( name=name, ) player.remote_address = remote_addr player.save() # write scores try: Score.objects.update_or_create( song=song, player=player, difficulty=difficulty, score=score, stars=stars, date=timestamp, version=version, instrument=song_instrument, ) except IntegrityError: return HttpResponse(False) return HttpResponse(True)
def __run(_bundlePath): # # Initializes the framework, verifies the plug-in & extracts information, then enters a # run loop for handling requests. # global Identifier global Debug global __bundlePath global __pluginModule global __logFilePath global __requestHandlers global LastPrefix FirstRun = False random.seed() # Set up the support file paths if sys.platform == "win32": if 'PLEXLOCALAPPDATA' in os.environ: key = 'PLEXLOCALAPPDATA' else: key = 'LOCALAPPDATA' pmsPath = os.path.join(os.environ[key], 'Plex Media Server') logFilesPath = os.path.join(os.environ[key], "Plex Media Server", "Logs", "PMS Plugin Logs") else: pmsPath = "%s/Library/Application Support/Plex Media Server" % os.environ[ "HOME"] logFilesPath = "%s/Library/Logs/Plex Media Server/PMS Plugin Logs" % os.environ[ "HOME"] supportFilesPath = "%s/Plug-in Support" % pmsPath frameworkSupportFilesPath = "%s/Framework Support" % pmsPath # Make sure framework directories exist def checkpath(path): try: if not os.path.exists(path): os.makedirs(path) except: pass checkpath("%s/Preferences" % supportFilesPath) checkpath("%s/Databases" % supportFilesPath) checkpath(logFilesPath) checkpath(frameworkSupportFilesPath) # Set the bundle path __bundlePath = _bundlePath.rstrip('/') # Add the bundle path to the system path, including any libraries if os.path.isdir("%s/Contents" % __bundlePath): sys.path.append("%s/Contents" % __bundlePath) if os.path.isdir("%s/Contents/Libraries" % __bundlePath): sys.path.append("%s/Contents/Libraries" % __bundlePath) else: print "Couldn't find bundle directory" return None # Open the Info.plist file f = open("%s/Contents/Info.plist" % __bundlePath, "r") infoplist = XML.ElementFromString(f.read()) f.close() if infoplist is None: print "Couldn't load Info.plist file from plug-in" return # Get the plug-in identifier Identifier = infoplist.xpath( '//key[text()="CFBundleIdentifier"]//following-sibling::string/text()' )[0] if Identifier is None: print "Invalid Info.plist file in plug-in" return None # Set up the log file __logFilePath = "%s/%s.log" % (logFilesPath, Identifier) if os.path.exists(__logFilePath): if os.path.exists("%s.old" % __logFilePath): os.remove("%s.old" % __logFilePath) os.rename(__logFilePath, "%s.old" % __logFilePath) # Now we can start logging PMS.Log("(Framework) Bundle verification complete", False) # Check whether debugging is enabled try: _debug = infoplist.xpath( '//key[text()="PlexPluginDebug"]//following-sibling::string/text()' )[0] if _debug == "1": Debug = True PMS.Log("(Framework) Debugging is enabled") except: pass # Log the system encoding (set during bootstrap) PMS.Log("(Framework) Default encoding is " + sys.getdefaultencoding()) # Set up framework paths Prefs.__prefsPath = "%s/Preferences/%s.xml" % (supportFilesPath, Identifier) Data.__dataPath = "%s/Data/%s" % (supportFilesPath, Identifier) Data.__dataItemPath = "%s/DataItems" % Data.__dataPath if not os.path.isdir(Data.__dataItemPath): FirstRun = True os.makedirs(Data.__dataItemPath) Resource.__resourcePath = "%s/Contents/Resources" % __bundlePath Helper.__helperPath = "%s/Contents/Helpers" % __bundlePath Resource.__sharedResourcePath = "%s/Plug-ins/Framework.bundle/Contents/Resources/Versions/1/Resources" % pmsPath Database.__databasePath = "%s/Databases/%s.db" % (supportFilesPath, Identifier) os.chdir(Data.__dataItemPath) Locale.SetDefaultLocale() PMS.Log("(Framework) Configured framework modules") # Attempt to import the plug-in module - if debugging is enabled, don't catch exceptions if Debug: import Code as _plugin PMS.Log("(Framework) Imported plug-in module") else: try: import Code as _plugin PMS.Log("(Framework) Imported plug-in module") except ImportError: PMS.Log("(Framework) Couldn't import plug-in from bundle") __exit() return # Load the list of trusted plug-ins _trusted = [] try: _trustedJSON = Resource.LoadShared("trust.json") if _trustedJSON: _trusted = JSON.ObjectFromString(_trustedJSON) except: pass # Populate the permission lists __setupPermissionLists() # Register the plug-in with the framework __pluginModule = _plugin # Check the imported module to make sure nothing untoward is happening! if Identifier in _trusted: PMS.Log("(Framework) Plug-in is trusted, skipping module check") else: __scanModules() _allowed = [] for n in PMS.__dict__: if n[0] != "_": if type(PMS.__dict__[n]).__name__ == "module": _allowed.append(n) for n in __modWhitelist: _allowed.append(n) __checkModule(_plugin, _allowed) PMS.Log("(Framework) Checked module imports") # Initialize the framework modules Dict.__load() if not FirstRun: __checkFrameworkCompatibility() Prefs.__load() HTTP.__loadCookieJar() HTTP.__loadCache() if HTTP_TIMEOUT_VAR_NAME in os.environ: HTTP.SetTimeout(float(os.environ[HTTP_TIMEOUT_VAR_NAME])) else: HTTP.SetTimeout(HTTP_DEFAULT_TIMEOUT) PMS.Log("(Framework) Initialized framework modules") # Call the plug-in's Start method PMS.Log("(Framework) Attempting to start the plug-in...") __call(__pluginModule.Start) PMS.Log("(Framework) Plug-in started", False) # Start timers __startCacheManager(firstRun=FirstRun) PMS.Log("(Framework) Entering run loop") # Enter a run loop to handle requests while True: try: # Read the input path = raw_input() path = path.lstrip("GET ").strip() LastPrefix = None # Read headers headers = {} stop = False while stop == False: line = raw_input() if len(line) == 1: stop = True else: split = string.split(line.strip(), ":", maxsplit=1) if len(split) == 2: headers[split[0].strip()] = split[1].strip() # Set the locale if headers.has_key("X-Plex-Language"): loc = headers["X-Plex-Language"].lower() Locale.__loadLocale(loc) # Set the version if headers.has_key("X-Plex-Version"): Client.__setVersion(headers["X-Plex-Version"]) PMS.Request.Headers.clear() PMS.Request.Headers.update(headers) req = urlparse.urlparse(path) path = req.path qs_args = cgi.parse_qs(req.query) kwargs = {} if 'function_args' in qs_args: try: unquoted_args = urllib.unquote(qs_args['function_args'][0]) decoded_args = PMS.String.Decode(unquoted_args) kwargs = cerealizer.loads(decoded_args) except: PMS.Log(PMS.Plugin.Traceback()) raise Exception("Unable to deserialize arguments") for arg_name in qs_args: if arg_name != 'function_args': kwargs[arg_name] = qs_args[arg_name][0] # First, try to match a connected route rpath = path for key in __prefixHandlers: if rpath.count(key, 0, len(key)) == 1: rpath = rpath[len(key):] break f, route_kwargs = MatchRoute(rpath) if f is not None: PMS.Log("(Framework) Handling route request : %s" % path, False) route_kwargs.update(kwargs) result = f(**route_kwargs) # No route, fall back to other path handling methods else: mpath = path if mpath[-1] == "/": mpath = mpath[:-1] # Split the path into components and decode. pathNouns = path.split('/') pathNouns = [urllib.unquote(p) for p in pathNouns] # If no input was given, return an error if len(pathNouns) <= 1: __return("%s\r\n\r\n" % PMS.Error['BadRequest']) # Otherwise, attempt to handle the request else: result = None pathNouns.pop(0) count = len(pathNouns) if pathNouns[-1] == "": pathNouns.pop(len(pathNouns) - 1) PMS.Log("(Framework) Handling request : %s" % path, False) # Check for a management request if pathNouns[0] == ":": result = __handlePMSRequest(pathNouns, path, **kwargs) else: handler = None isPrefixHandler = False # See if there's a prefix handler available for key in __prefixHandlers: if mpath.count(key, 0, len(key)) == 1: LastPrefix = key if mpath in __prefixHandlers: handler = __prefixHandlers[mpath]["handler"] isPrefixHandler = True else: # Check each request handler to see if it handles the current prefix popped = False for key in __requestHandlers: if handler is None: if path.count(key, 0, len(key)) == 1: # Remove the prefix from the path keyNounCount = len(key.split('/')) - 1 for i in range(keyNounCount): pathNouns.pop(0) count = count - keyNounCount # Find the request handler handler = __requestHandlers[key][ "handler"] LastPrefix = key popped = True # If no path request handler was found, make sure we still pop the prefix so internal requests work for key in __prefixHandlers: if popped == False: if mpath.count(key, 0, len(key)) == 1: keyNounCount = len(key.split('/')) - 1 for i in range(keyNounCount): pathNouns.pop(0) popped = True # Check whether we should handle the request internally handled = False if count > 0: if pathNouns[0] == ":": handled = True result = __handleInternalRequest( pathNouns, path, **kwargs) # Check if the App Store has flagged the plug-in as broken if os.path.exists( os.path.join(frameworkSupportFilesPath, "%s.broken" % Identifier)): #TODO: Localise this bit, use message from the App Store if available handled = True result = PMS.Objects.MessageContainer( "Please try again later", "This plug-in is currently unavailable") PMS.Log("(Framework) Plug-in is flagged as broken") # If the request hasn't been handled, and we have a valid request handler, call it else: if not handled and handler is not None: if isPrefixHandler: result = handler(**kwargs) else: result = handler(pathNouns, path, **kwargs) response = None # If the request wasn't handled, return an error if result == None: PMS.Log("(Framework) Request not handled by plug-in", False) response = "%s\r\n\r\n" % PMS.Error['NotFound'] # If the plugin returned an error, return it to PMS elif result in PMS.Error.values(): PMS.Log("(Framework) Plug-in returned an error : %s" % result, False) response = "%s\r\n\r\n" % result # Otherwise, check if a valid object was returned, and return the result elif __objectManager.ObjectHasBase(result, Objects.Object): resultStr = result.Content() resultStatus = result.Status() resultHeaders = result.Headers() elif isinstance(result, basestring): resultStr = result resultStatus = '200 OK' resultHeaders = "Content-type: text/plain\r\n" if resultStr is not None: PMS.Log("(Framework) Response OK") resultLen = len(resultStr) if resultLen > 0: resultHeaders += "Content-Length: %i\r\n" % resultLen resultStr = "\r\n" + resultStr else: resultStr = "" resultStatus = '500 Internal Server Error' resultHeaders = '' PMS.Log("(Framework) Unknown response type") if response == None: response = str("%s\r\n%s" % (resultStatus, resultHeaders)) + str(resultStr) + str("\r\n") #PMS.Log("\n---\n"+response+"---\n") __return(response) # If a KeyboardInterrupt (SIGINT) is raised, stop the plugin except KeyboardInterrupt: # Save data & exit __saveData() __exit() except EOFError: # Save data & exit __saveData() __exit() # If another exception is raised, deal with the problem except: __except() __return("%s\r\n\r\n" % PMS.Error['InternalError']) # Make sure the plugin's data is saved finally: __saveData()
def __run(_bundlePath): # # Initializes the framework, verifies the plug-in & extracts information, then enters a # run loop for handling requests. # global Identifier global Debug global __bundlePath global __pluginModule global __logFilePath global __requestHandlers global LastPrefix FirstRun = False random.seed() # Set up the support file paths if sys.platform == "win32": if 'PLEXLOCALAPPDATA' in os.environ: key = 'PLEXLOCALAPPDATA' else: key = 'LOCALAPPDATA' pmsPath = os.path.join(os.environ[key], 'Plex Media Server') logFilesPath = os.path.join(os.environ[key], "Plex Media Server", "Logs", "PMS Plugin Logs") else: pmsPath = "%s/Library/Application Support/Plex Media Server" % os.environ["HOME"] logFilesPath = "%s/Library/Logs/PMS Plugin Logs" % os.environ["HOME"] supportFilesPath = "%s/Plug-in Support" % pmsPath frameworkSupportFilesPath = "%s/Framework Support" % pmsPath # Make sure framework directories exist def checkpath(path): try: if not os.path.exists(path): os.makedirs(path) except: pass checkpath("%s/Preferences" % supportFilesPath) checkpath("%s/Databases" % supportFilesPath) checkpath(logFilesPath) checkpath(frameworkSupportFilesPath) # Set the bundle path __bundlePath = _bundlePath.rstrip('/') # Add the bundle path to the system path, including any libraries if os.path.isdir("%s/Contents" % __bundlePath): sys.path.append("%s/Contents" % __bundlePath) if os.path.isdir("%s/Contents/Libraries" % __bundlePath): sys.path.append("%s/Contents/Libraries" % __bundlePath) else: print "Couldn't find bundle directory" return None # Open the Info.plist file f = open("%s/Contents/Info.plist" % __bundlePath, "r") infoplist = XML.ElementFromString(f.read()) f.close() if infoplist is None: print "Couldn't load Info.plist file from plug-in" return # Get the plug-in identifier Identifier = infoplist.xpath('//key[text()="CFBundleIdentifier"]//following-sibling::string/text()')[0] if Identifier is None: print "Invalid Info.plist file in plug-in" return None # Set up the log file __logFilePath = "%s/%s.log" % (logFilesPath, Identifier) if os.path.exists(__logFilePath): if os.path.exists("%s.old" % __logFilePath): os.remove("%s.old" % __logFilePath) os.rename(__logFilePath, "%s.old" % __logFilePath) # Now we can start logging PMS.Log("(Framework) Bundle verification complete", False) # Check whether debugging is enabled try: _debug = infoplist.xpath('//key[text()="PlexPluginDebug"]//following-sibling::string/text()')[0] if _debug == "1": Debug = True PMS.Log("(Framework) Debugging is enabled") except: pass # Log the system encoding (set during bootstrap) PMS.Log("(Framework) Default encoding is " + sys.getdefaultencoding()) # Set up framework paths Prefs.__prefsPath = "%s/Preferences/%s.xml" % (supportFilesPath, Identifier) Data.__dataPath = "%s/Data/%s" % (supportFilesPath, Identifier) Data.__dataItemPath = "%s/DataItems" % Data.__dataPath if not os.path.isdir(Data.__dataItemPath): FirstRun = True os.makedirs(Data.__dataItemPath) Resource.__resourcePath = "%s/Contents/Resources" % __bundlePath Helper.__helperPath = "%s/Contents/Helpers" % __bundlePath Resource.__sharedResourcePath = "%s/Plug-ins/Framework.bundle/Contents/Resources/Versions/1/Resources" % pmsPath Database.__databasePath = "%s/Databases/%s.db" % (supportFilesPath, Identifier) os.chdir(Data.__dataItemPath) Locale.SetDefaultLocale() PMS.Log("(Framework) Configured framework modules") # Attempt to import the plug-in module - if debugging is enabled, don't catch exceptions if Debug: import Code as _plugin PMS.Log("(Framework) Imported plug-in module") else: try: import Code as _plugin PMS.Log("(Framework) Imported plug-in module") except ImportError: PMS.Log("(Framework) Couldn't import plug-in from bundle") __exit() return # Load the list of trusted plug-ins _trusted = [] try: _trustedJSON = Resource.LoadShared("trust.json") if _trustedJSON: _trusted = JSON.ObjectFromString(_trustedJSON) except: pass # Populate the permission lists __setupPermissionLists() # Register the plug-in with the framework __pluginModule = _plugin # Check the imported module to make sure nothing untoward is happening! if Identifier in _trusted: PMS.Log("(Framework) Plug-in is trusted, skipping module check") else: __scanModules() _allowed = [] for n in PMS.__dict__: if n[0] != "_": if type(PMS.__dict__[n]).__name__ == "module": _allowed.append(n) for n in __modWhitelist: _allowed.append(n) __checkModule(_plugin, _allowed) PMS.Log("(Framework) Checked module imports") # Initialize the framework modules Dict.__load() if not FirstRun: __checkFrameworkCompatibility() Prefs.__load() HTTP.__loadCookieJar() HTTP.__loadCache() if HTTP_TIMEOUT_VAR_NAME in os.environ: HTTP.SetTimeout(float(os.environ[HTTP_TIMEOUT_VAR_NAME])) else: HTTP.SetTimeout(HTTP_DEFAULT_TIMEOUT) PMS.Log("(Framework) Initialized framework modules") # Call the plug-in's Start method PMS.Log("(Framework) Attempting to start the plug-in...") __call(__pluginModule.Start) PMS.Log("(Framework) Plug-in started", False) # Start timers __startCacheManager(firstRun=FirstRun) PMS.Log("(Framework) Entering run loop") # Enter a run loop to handle requests while True: try: # Read the input path = raw_input() path = path.lstrip("GET ").strip() LastPrefix = None # Read headers headers = {} stop = False while stop == False: line = raw_input() if len(line) == 1: stop = True else: split = string.split(line.strip(), ":", maxsplit=1) if len(split) == 2: headers[split[0].strip()] = split[1].strip() # Set the locale if headers.has_key("X-Plex-Language"): loc = headers["X-Plex-Language"].lower() Locale.__loadLocale(loc) # Set the version if headers.has_key("X-Plex-Version"): Client.__setVersion(headers["X-Plex-Version"]) PMS.Request.Headers.clear() PMS.Request.Headers.update(headers) req = urlparse.urlparse(path) path = req.path qs_args = cgi.parse_qs(req.query) kwargs = {} if 'function_args' in qs_args: try: unquoted_args = urllib.unquote(qs_args['function_args'][0]) decoded_args = PMS.String.Decode(unquoted_args) kwargs = cerealizer.loads(decoded_args) except: PMS.Log(PMS.Plugin.Traceback()) raise Exception("Unable to deserialize arguments") for arg_name in qs_args: if arg_name != 'function_args': kwargs[arg_name] = qs_args[arg_name][0] # First, try to match a connected route rpath = path for key in __prefixHandlers: if rpath.count(key, 0, len(key)) == 1: rpath = rpath[len(key):] break f, route_kwargs = MatchRoute(rpath) if f is not None: PMS.Log("(Framework) Handling route request : %s" % path, False) route_kwargs.update(kwargs) result = f(**route_kwargs) # No route, fall back to other path handling methods else: mpath = path if mpath[-1] == "/": mpath = mpath[:-1] # Split the path into components and decode. pathNouns = path.split('/') pathNouns = [urllib.unquote(p) for p in pathNouns] # If no input was given, return an error if len(pathNouns) <= 1: __return("%s\r\n\r\n" % PMS.Error['BadRequest']) # Otherwise, attempt to handle the request else: result = None pathNouns.pop(0) count = len(pathNouns) if pathNouns[-1] == "": pathNouns.pop(len(pathNouns)-1) PMS.Log("(Framework) Handling request : %s" % path, False) # Check for a management request if pathNouns[0] == ":": result = __handlePMSRequest(pathNouns, path, **kwargs) else: handler = None isPrefixHandler = False # See if there's a prefix handler available for key in __prefixHandlers: if mpath.count(key, 0, len(key)) == 1: LastPrefix = key if mpath in __prefixHandlers: handler = __prefixHandlers[mpath]["handler"] isPrefixHandler = True else: # Check each request handler to see if it handles the current prefix popped = False for key in __requestHandlers: if handler is None: if path.count(key, 0, len(key)) == 1: # Remove the prefix from the path keyNounCount = len(key.split('/')) - 1 for i in range(keyNounCount): pathNouns.pop(0) count = count - keyNounCount # Find the request handler handler = __requestHandlers[key]["handler"] LastPrefix = key popped = True # If no path request handler was found, make sure we still pop the prefix so internal requests work for key in __prefixHandlers: if popped == False: if mpath.count(key, 0, len(key)) == 1: keyNounCount = len(key.split('/')) - 1 for i in range(keyNounCount): pathNouns.pop(0) popped = True # Check whether we should handle the request internally handled = False if count > 0: if pathNouns[0] == ":": handled = True result = __handleInternalRequest(pathNouns, path, **kwargs) # Check if the App Store has flagged the plug-in as broken if os.path.exists(os.path.join(frameworkSupportFilesPath, "%s.broken" % Identifier)): #TODO: Localise this bit, use message from the App Store if available handled = True result = PMS.Objects.MessageContainer("Please try again later", "This plug-in is currently unavailable") PMS.Log("(Framework) Plug-in is flagged as broken") # If the request hasn't been handled, and we have a valid request handler, call it else: if not handled and handler is not None: if isPrefixHandler: result = handler(**kwargs) else: result = handler(pathNouns, path, **kwargs) response = None # If the request wasn't handled, return an error if result == None: PMS.Log("(Framework) Request not handled by plug-in", False) response = "%s\r\n\r\n" % PMS.Error['NotFound'] # If the plugin returned an error, return it to PMS elif result in PMS.Error.values(): PMS.Log("(Framework) Plug-in returned an error : %s" % result, False) response = "%s\r\n\r\n" % result # Otherwise, check if a valid object was returned, and return the result elif __objectManager.ObjectHasBase(result, Objects.Object): resultStr = result.Content() resultStatus = result.Status() resultHeaders = result.Headers() elif isinstance(result, basestring): resultStr = result resultStatus = '200 OK' resultHeaders = "Content-type: text/plain\r\n" if resultStr is not None: PMS.Log("(Framework) Response OK") resultLen = len(resultStr) if resultLen > 0: resultHeaders += "Content-Length: %i\r\n" % resultLen resultStr = "\r\n"+resultStr else: resultStr = "" resultStatus = '500 Internal Server Error' resultHeaders = '' PMS.Log("(Framework) Unknown response type") if response == None: response = str("%s\r\n%s" % (resultStatus, resultHeaders)) + str(resultStr) + str("\r\n") #PMS.Log("\n---\n"+response+"---\n") __return(response) # If a KeyboardInterrupt (SIGINT) is raised, stop the plugin except KeyboardInterrupt: # Save data & exit __saveData() __exit() except EOFError: # Save data & exit __saveData() __exit() # If another exception is raised, deal with the problem except: __except() __return("%s\r\n\r\n" % PMS.Error['InternalError']) # Make sure the plugin's data is saved finally: __saveData()