Skip to content
Browse files

initial commit

  • Loading branch information...
0 parents commit fc96564144d6e9a17cf68e18c9d078d1266996f8 Alvaro Videla committed Jan 21, 2010
Showing with 305 additions and 0 deletions.
  1. +23 −0 LICENSE
  2. +185 −0 PHPUnserialize.py
  3. +18 −0 README.md
  4. 0 __init__.py
  5. +14 −0 conf.py
  6. +65 −0 session_inspector.py
23 LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2010 Alvaro Videla <videlalvaro@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+PHPUnserialize taken from http://hurring.com/code/python/phpserialize/
+with modified version of session_decode by me
185 PHPUnserialize.py
@@ -0,0 +1,185 @@
+import types, string, re
+
+"""
+Unserialize class for the PHP serialization format.
+
+@version v0.4 BETA
+@author Scott Hurring; scott at hurring dot com
+@copyright Copyright (c) 2005 Scott Hurring
+@license http://opensource.org/licenses/gpl-license.php GNU Public License
+$Id: PHPUnserialize.py,v 1.1 2006/01/08 21:53:19 shurring Exp $
+
+Most recent version can be found at:
+http://hurring.com/code/python/phpserialize/
+
+Usage:
+# Create an instance of the unserialize engine
+u = PHPUnserialize()
+# unserialize some string into python data
+data = u.unserialize(serialized_string)
+
+Please see README.txt for more information.
+"""
+
+class PHPUnserialize(object):
+ """
+ Class to unserialize something from the PHP Serialize format.
+
+ Usage:
+ u = PHPUnserialize()
+ data = u.unserialize(serialized_string)
+ """
+
+ def __init__(self):
+ pass
+
+ def session_decode(self, data):
+ """Thanks to Ken Restivo for suggesting the addition
+ of session_encode
+ """
+ session = {}
+ while len(data) > 0:
+ (offset, key) = self.read_until(data, 0, '|')
+ if offset > 0:
+ (dtype, dataoffset, value) = self._unserialize(data, offset+1)
+ data = data[offset+1+dataoffset:]
+ session[key] = value
+ else:
+ return session
+
+ return session
+
+ def unserialize(self, data):
+ return self._unserialize(data, 0)[2]
+
+ def _unserialize(self, data, offset=0):
+ """
+ Find the next token and unserialize it.
+ Recurse on array.
+
+ offset = raw offset from start of data
+
+ return (type, offset, value)
+ """
+
+ buf = []
+ dtype = string.lower(data[offset:offset+1])
+
+ #print "# dtype =", dtype
+
+ # 't:' = 2 chars
+ dataoffset = offset + 2
+ typeconvert = lambda x : x
+ chars = datalength = 0
+
+ # int => Integer
+ if dtype == 'i':
+ typeconvert = lambda x : int(x)
+ (chars, readdata) = self.read_until(data, dataoffset, ';')
+ # +1 for end semicolon
+ dataoffset += chars + 1
+
+ # bool => Boolean
+ elif dtype == 'b':
+ typeconvert = lambda x : (int(x) == 1)
+ (chars, readdata) = self.read_until(data, dataoffset, ';')
+ # +1 for end semicolon
+ dataoffset += chars + 1
+
+ # double => Floating Point
+ elif dtype == 'd':
+ typeconvert = lambda x : float(x)
+ (chars, readdata) = self.read_until(data, dataoffset, ';')
+ # +1 for end semicolon
+ dataoffset += chars + 1
+
+ # n => None
+ elif dtype == 'n':
+ readdata = None
+
+ # s => String
+ elif dtype == 's':
+ (chars, stringlength) = self.read_until(data, dataoffset, ':')
+ # +2 for colons around length field
+ dataoffset += chars + 2
+
+ # +1 for start quote
+ (chars, readdata) = self.read_chars(data, dataoffset+1, int(stringlength))
+ # +2 for endquote semicolon
+ dataoffset += chars + 2
+
+ if chars != int(stringlength) != int(readdata):
+ raise Exception("String length mismatch")
+
+ # array => Dict
+ # If you originally serialized a Tuple or List, it will
+ # be unserialized as a Dict. PHP doesn't have tuples or lists,
+ # only arrays - so everything has to get converted into an array
+ # when serializing and the original type of the array is lost
+ elif dtype == 'a':
+ readdata = {}
+
+ # How many keys does this list have?
+ (chars, keys) = self.read_until(data, dataoffset, ':')
+ # +2 for colons around length field
+ dataoffset += chars + 2
+
+ # Loop through and fetch this number of key/value pairs
+ for i in range(0, int(keys)):
+ # Read the key
+ (ktype, kchars, key) = self._unserialize(data, dataoffset)
+ dataoffset += kchars
+ #print "Key(%i) = (%s, %i, %s) %i" % (i, ktype, kchars, key, dataoffset)
+
+ # Read value of the key
+ (vtype, vchars, value) = self._unserialize(data, dataoffset)
+ dataoffset += vchars
+ #print "Value(%i) = (%s, %i, %s) %i" % (i, vtype, vchars, value, dataoffset)
+
+ # Set the list element
+ readdata[key] = value
+
+ # +1 for end semicolon
+ dataoffset += 1
+ #chars = int(dataoffset) - start
+
+ # I don't know how to unserialize this
+ else:
+ raise Exception("Unknown / Unhandled data type (%s)!" % dtype)
+
+
+ return (dtype, dataoffset-offset, typeconvert(readdata))
+
+ def read_until(self, data, offset, stopchar):
+ """
+ Read from data[offset] until you encounter some char 'stopchar'.
+ """
+ buf = []
+ char = data[offset:offset+1]
+ i = 2
+ while char != stopchar:
+ # Consumed all the characters and havent found ';'
+ if i+offset > len(data):
+ raise Exception("Invalid")
+ buf.append(char)
+ char = data[offset+(i-1):offset+i]
+ i += 1
+
+ # (chars_read, data)
+ return (len(buf), "".join(buf))
+
+ def read_chars(self, data, offset, length):
+ """
+ Read 'length' number of chars from data[offset].
+ """
+ buf = []
+ # Account for the starting quote char
+ #offset += 1
+ for i in range(0, length):
+ char = data[offset+(i-1):offset+i]
+ buf.append(char)
+
+ # (chars_read, data)
+ return (len(buf), "".join(buf))
+
+
18 README.md
@@ -0,0 +1,18 @@
+usage:
+
+python session_inspector.py
+
+Commands:
+isauth session_id1 session_id2 session_id3
+
+returns 0 or 1 if the user of that session id is authenticated
+each line of the response corresponds to one of the key passed
+the lines are ended by \r\n
+
+quit
+closes the connection to the server
+
+>telnet localhost 3002
+isauth session_id
+isauth session_ida session_idb session_idc
+quit
0 __init__.py
No changes.
14 conf.py
@@ -0,0 +1,14 @@
+INSPECTOR_INTERFACE='0.0.0.0'
+INSPECTOR_PORT=3002
+
+# if you have several servers with different weigths, then try something like:
+# sessServers = (['127.0.0.1:11211'] * 3) + (['127.0.0.1:11212'] * 5)
+# where 3 and 5 are the weigths defined for those servers in Memcache::addServer in PHP
+sessServers = ['127.0.0.1:11211']
+
+#memcache key prefix, use '' if none set.
+prefix = ''
+
+# key inside the session array that stores if the user is authenticated or not
+# for example this is what symfony uses
+auth_key = 'symfony/user/sfUser/authenticated'
65 session_inspector.py
@@ -0,0 +1,65 @@
+from twisted.internet import reactor
+from twisted.internet.protocol import Factory
+from twisted.internet.error import ConnectionDone
+from twisted.protocols.basic import LineOnlyReceiver
+import memcache
+import sys
+from PHPUnserialize import *
+from conf import *
+
+mc = memcache.Client(sessServers, debug=0)
+
+class InspectorReceiver(LineOnlyReceiver):
+ delimiter = '\r\n'
+
+ def connectionMade(self):
+ self.peer = self.transport.getPeer()
+ self.peerAddr = "%s:%d" % (self.peer.host, self.peer.port)
+ print("%s connection with %s established" % (self.__class__.__name__, self.peerAddr))
+
+ def connectionLost(self, reason):
+ if reason.check(ConnectionDone):
+ print("%s connection with %s closed cleanly" % (self.__class__.__name__, self.peerAddr))
+ else:
+ print("%s connection with %s lost: %s" % (self.__class__.__name__, self.peerAddr, reason.value))
+
+ def isAuth(self, is_auth):
+ self.transport.write("%d\r\n" % (is_auth, ))
+
+ def lineReceived(self, line):
+ global mc, prefix, auth_key
+
+ try:
+ values = line.strip().split()
+
+ if len(values) < 1:
+ pass
+
+ if values[0] == 'isauth' and len(values) > 1:
+ for key in values[1:]:
+ data = mc.get(prefix + key)
+ if not data:
+ self.isAuth(False)
+ else:
+ try:
+ session = PHPUnserialize().session_decode(data)
+ self.isAuth(session[auth_key])
+ except:
+ self.isAuth(False)
+
+ elif values[0] == 'quit':
+ self.transport.loseConnection()
+ else:
+ raise Exception('Invalid command')
+ except:
+ print('invalid line received from client %s' % self.peerAddr)
+ return
+
+def startListener(interface, port, protocol):
+ factory = Factory()
+ factory.protocol = protocol
+ return reactor.listenTCP( int(port), factory, interface=interface )
+
+startListener(INSPECTOR_INTERFACE, INSPECTOR_PORT, InspectorReceiver)
+
+reactor.run()

0 comments on commit fc96564

Please sign in to comment.
Something went wrong with that request. Please try again.