class FSFile(FSObject): """FSFiles act like images but are not directly modifiable from the management interface.""" # Note that OFS.Image.File is not a base class because it is mutable. meta_type = 'Filesystem File' manage_options = ({ 'label': 'Customize', 'action': 'manage_main' }, ) + Cacheable.manage_options security = ClassSecurityInfo() security.declareObjectProtected(View) def __init__(self, id, filepath, fullname=None, properties=None): id = fullname or id # Use the whole filename. FSObject.__init__(self, id, filepath, fullname, properties) security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = Globals.DTMLFile('custfile', _dtmldir) content_type = 'unknown/unknown' def _createZODBClone(self): return File(self.getId(), '', self._readFile(1)) def _get_content_type(self, file, body, id, content_type=None): headers = getattr(file, 'headers', None) if headers and headers.has_key('content-type'): content_type = headers['content-type'] else: if type(body) is not type(''): body = body.data content_type, enc = guess_content_type( getattr(file, 'filename', id), body, content_type) return content_type def _readFile(self, reparse): fp = expandpath(self._filepath) file = open(fp, 'rb') try: data = file.read() finally: file.close() if reparse or self.content_type == 'unknown/unknown': self.ZCacheable_invalidate() self.content_type = self._get_content_type(file, data, self.id) return data #### The following is mainly taken from OFS/File.py ### __str__ = File.__str__ security.declareProtected(View, 'index_html') def index_html(self, REQUEST, RESPONSE): """ The default view of the contents of a File or Image. Returns the contents of the file or image. Also, sets the Content-Type HTTP header to the objects content type. """ self._updateFromFS() data = self._readFile(0) # HTTP If-Modified-Since header handling. header = REQUEST.get_header('If-Modified-Since', None) if header is not None: header = string.split(header, ';')[0] # Some proxies seem to send invalid date strings for this # header. If the date string is not valid, we ignore it # rather than raise an error to be generally consistent # with common servers such as Apache (which can usually # understand the screwy date string as a lucky side effect # of the way they parse it). try: mod_since = long(DateTime(header).timeTime()) except: mod_since = None if mod_since is not None: last_mod = self._file_mod_time if last_mod > 0 and last_mod <= mod_since: # Set header values since apache caching will return # Content-Length of 0 in response if size is not set here RESPONSE.setHeader('Last-Modified', rfc1123_date(last_mod)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', self.get_size()) RESPONSE.setStatus(304) return '' RESPONSE.setHeader('Last-Modified', rfc1123_date(self._file_mod_time)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', len(data)) self.ZCacheable_set(None) return data security.declareProtected(View, 'getContentType') def getContentType(self): """Get the content type of a file or image. Returns the content type (MIME type) of a file or image. """ self._updateFromFS() return self.content_type security.declareProtected(FTPAccess, 'manage_FTPget') manage_FTPget = index_html
class FSSTXMethod( FSObject ): """ A chunk of StructuredText, rendered as a skin method of a CMFSite. """ meta_type = 'Filesystem STX Method' manage_options=( { 'label' : 'Customize' , 'action' : 'manage_main' } , { 'label' : 'View' , 'action' : '' , 'help' : ('OFSP' ,'DTML-DocumentOrMethod_View.stx' ) } ) security = ClassSecurityInfo() security.declareObjectProtected( View ) security.declareProtected( ViewManagementScreens, 'manage_main') manage_main = Globals.DTMLFile( 'custstx', _dtmldir ) # # FSObject interface # def _createZODBClone(self): """ Create a ZODB (editable) equivalent of this object. """ raise NotImplementedError, "See next week's model." def _readFile( self, reparse ): fp = expandpath( self._filepath ) file = open( fp, 'r' ) # not binary, we want CRLF munging here. try: data = file.read() finally: file.close() self.raw = data if reparse: self.cook() # # "Wesleyan" interface (we need to be "methodish"). # class func_code: pass func_code=func_code() func_code.co_varnames= () func_code.co_argcount=0 func_code.__roles__=() func_defaults__roles__=() func_defaults=() index_html = None # No accidental acquisition default_content_type = 'text/html' def cook( self ): if not hasattr( self, '_v_cooked' ): self._v_cooked = HTML(self.raw, level=1, header=0) return self._v_cooked _default_template = Globals.HTML( """\ <dtml-var standard_html_header> <div class="Desktop"> <dtml-var cooked> </div> <dtml-var standard_html_footer>""" ) def __call__( self, REQUEST={}, RESPONSE=None, **kw ): """ Return our rendered StructuredText. """ self._updateFromFS() if RESPONSE is not None: RESPONSE.setHeader( 'Content-Type', 'text/html' ) return self._render(REQUEST, RESPONSE, **kw) security.declarePrivate( '_render' ) def _render( self, REQUEST={}, RESPONSE=None, **kw ): """ Find the appropriate rendering template and use it to render us. """ template = getattr( self, 'stxmethod_view', self._default_template ) if getattr( template, 'isDocTemp', 0 ): posargs = ( self, REQUEST, RESPONSE ) else: posargs = () return template(*posargs, **{ 'cooked' : self.cook() } ) security.declareProtected( FTPAccess, 'manage_FTPget' ) def manage_FTPget( self ): """ Fetch our source for delivery via FTP. """ return self.raw security.declareProtected( ViewManagementScreens, 'PrincipiaSearchSource' ) def PrincipiaSearchSource( self ): """ Fetch our source for indexing in a catalog. """ return self.raw security.declareProtected( ViewManagementScreens, 'document_src' ) def document_src( self ): """ Fetch our source for indexing in a catalog. """ return self.raw
class FSPythonScript (FSObject, Script): """FSPythonScripts act like Python Scripts but are not directly modifiable from the management interface.""" meta_type = 'Filesystem Script (Python)' _params = _body = '' _v_f = None manage_options=( ( {'label':'Customize', 'action':'manage_main'}, {'label':'Test', 'action':'ZScriptHTML_tryForm', 'help': ('PythonScripts', 'PythonScript_test.stx')}, ) ) # Use declarative security security = ClassSecurityInfo() security.declareObjectProtected(View) security.declareProtected(View, 'index_html',) # Prevent the bindings from being edited TTW security.declarePrivate('ZBindings_edit','ZBindingsHTML_editForm','ZBindingsHTML_editAction') security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = Globals.DTMLFile('custpy', _dtmldir) def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" obj = PythonScript(self.getId()) obj.write(self.read()) return obj def _readFile(self, reparse): """Read the data from the filesystem. Read the file (indicated by exandpath(self._filepath), and parse the data if necessary. """ fp = expandpath(self._filepath) file = open(fp, 'r') try: data = file.read() finally: file.close() if reparse: self._write(data, reparse) def _validateProxy(self, roles=None): pass def __render_with_namespace__(self, namespace): '''Calls the script.''' self._updateFromFS() return Script.__render_with_namespace__(self, namespace) def __call__(self, *args, **kw): '''Calls the script.''' self._updateFromFS() return Script.__call__(self, *args, **kw) #### The following is mainly taken from PythonScript.py ### def _exec(self, bound_names, args, kw): """Call a Python Script Calling a Python Script is an actual function invocation. """ # Prepare the function. f = self._v_f if f is None: # The script has errors. raise RuntimeError, '%s has errors.' % self._filepath __traceback_info__ = bound_names, args, kw, self.func_defaults if bound_names: # Updating func_globals directly is not thread safe here. # In normal PythonScripts, every thread has its own # copy of the function. But in FSPythonScripts # there is only one copy. So here's another way. new_globals = f.func_globals.copy() new_globals.update(bound_names) if f.func_defaults: f = new.function(f.func_code, new_globals, f.func_name, f.func_defaults) else: f = new.function(f.func_code, new_globals, f.func_name) # Execute the function in a new security context. security=getSecurityManager() security.addContext(self) try: result = apply(f, args, kw) return result finally: security.removeContext(self) security.declareProtected(ViewManagementScreens, 'read', 'getModTime', 'get_size', 'ZScriptHTML_tryForm', 'PrincipiaSearchSource', 'document_src', 'params', 'body') def ZScriptHTML_tryParams(self): """Parameters to test the script with.""" param_names = [] for name in split(self._params, ','): name = strip(name) if name and name[0] != '*': param_names.append(split(name, '=', 1)[0]) return param_names def read(self): self._updateFromFS() return self._source def document_src(self, REQUEST=None, RESPONSE=None): """Return unprocessed document source.""" if RESPONSE is not None: RESPONSE.setHeader('Content-Type', 'text/plain') return self._source def PrincipiaSearchSource(self): "Support for searching - the document's contents are searched." return "%s\n%s" % (self._params, self._body) def params(self): return self._params def body(self): return self._body def get_size(self): return len(self.read()) security.declareProtected(FTPAccess, 'manage_FTPget') def manage_FTPget(self): "Get source for FTP download" self.REQUEST.RESPONSE.setHeader('Content-Type', 'text/plain') return self.read() def _write(self, text, compile): ''' Parses the source, storing the body, params, title, bindings, and source in self. If compile is set, compiles the function. ''' ps = PythonScript(self.id) ps.write(text) if compile: ps._makeFunction(1) self._v_f = f = ps._v_f if f is not None: self.func_code = f.func_code self.func_defaults = f.func_defaults else: # There were errors in the compile. # No signature. self.func_code = None self.func_defaults = None self._body = ps._body self._params = ps._params self.title = ps.title self._setupBindings(ps.getBindingAssignments().getAssignedNames()) self._source = ps.read() # Find out what the script sees. def func_defaults(self): # This ensures func_code and func_defaults are # set when the code hasn't been compiled yet, # just in time for mapply(). Truly odd, but so is mapply(). :P self._updateFromFS() return self.__dict__.get('func_defaults', None) func_defaults = ComputedAttribute(func_defaults, 1) def func_code(self): # See func_defaults. self._updateFromFS() return self.__dict__.get('func_code', None) func_code = ComputedAttribute(func_code, 1) def title(self): # See func_defaults. self._updateFromFS() return self.__dict__.get('title', None) title = ComputedAttribute(title, 1)
class FSFile(FSObject): """FSFiles act like images but are not directly modifiable from the management interface.""" # Note that OFS.Image.File is not a base class because it is mutable. meta_type = 'Filesystem File' manage_options = ({ 'label': 'Customize', 'action': 'manage_main' }, ) + Cacheable.manage_options security = ClassSecurityInfo() security.declareObjectProtected(View) def __init__(self, id, filepath, fullname=None, properties=None): id = fullname or id # Use the whole filename. FSObject.__init__(self, id, filepath, fullname, properties) security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = Globals.DTMLFile('custfile', _dtmldir) content_type = 'unknown/unknown' def _createZODBClone(self): return File(self.getId(), '', self._readFile(1)) def _get_content_type(self, file, body, id, content_type=None): # Consult self.content_type first, this is either # the default (unknown/unknown) or it got a value from a # .metadata file default_type = 'unknown/unknown' if getattr(self, 'content_type', default_type) != default_type: return self.content_type # Next, look at file headers headers = getattr(file, 'headers', None) if headers and headers.has_key('content-type'): content_type = headers['content-type'] else: # Last resort: Use the (imperfect) content type guessing # mechanism from OFS.Image, which ultimately uses the # Python mimetypes module. if not isinstance(body, basestring): body = body.data content_type, enc = guess_content_type( getattr(file, 'filename', id), body, content_type) if (enc is None and (content_type.startswith('text/') or content_type.startswith('application/')) and body.startswith(codecs.BOM_UTF8)): content_type += '; charset=utf-8' return content_type def _readFile(self, reparse): fp = expandpath(self._filepath) file = open(fp, 'rb') try: data = file.read() finally: file.close() if reparse or self.content_type == 'unknown/unknown': self.ZCacheable_invalidate() self.content_type = self._get_content_type(file, data, self.id) return data #### The following is mainly taken from OFS/File.py ### def __str__(self): self._updateFromFS() return str(self._readFile(0)) def modified(self): return self.getModTime() security.declareProtected(View, 'index_html') def index_html(self, REQUEST, RESPONSE): """ The default view of the contents of a File or Image. Returns the contents of the file or image. Also, sets the Content-Type HTTP header to the objects content type. """ self._updateFromFS() view = _ViewEmulator().__of__(self) # If we have a conditional get, set status 304 and return # no content if _checkConditionalGET(view, extra_context={}): return '' RESPONSE.setHeader('Content-Type', self.content_type) # old-style If-Modified-Since header handling. if self._setOldCacheHeaders(): # Make sure the CachingPolicyManager gets a go as well _setCacheHeaders(view, extra_context={}) return '' data = self._readFile(0) data_len = len(data) RESPONSE.setHeader('Content-Length', data_len) #There are 2 Cache Managers which can be in play.... #need to decide which to use to determine where the cache headers #are decided on. if self.ZCacheable_getManager() is not None: self.ZCacheable_set(None) else: _setCacheHeaders(view, extra_context={}) return data def _setOldCacheHeaders(self): # return False to disable this simple caching behaviour return _FSCacheHeaders(self) security.declareProtected(View, 'getContentType') def getContentType(self): """Get the content type of a file or image. Returns the content type (MIME type) of a file or image. """ self._updateFromFS() return self.content_type security.declareProtected(FTPAccess, 'manage_FTPget') manage_FTPget = index_html
class FSZSQLMethod(SQL, FSObject): """FSZSQLMethods act like Z SQL Methods but are not directly modifiable from the management interface.""" meta_type = 'Filesystem Z SQL Method' manage_options = ( { 'label': 'Customize', 'action': 'manage_customise' }, { 'label': 'Test', 'action': 'manage_testForm', 'help': ('ZSQLMethods', 'Z-SQL-Method_Test.stx') }, ) security = ClassSecurityInfo() security.declareObjectProtected(View) # Make mutators private security.declarePrivate('manage_main') security.declarePrivate('manage_edit') security.declarePrivate('manage_advanced') security.declarePrivate('manage_advancedForm') manage = None security.declareProtected(ViewManagementScreens, 'manage_customise') manage_customise = Globals.DTMLFile('custzsql', _dtmldir) def __init__(self, id, filepath, fullname=None, properties=None): FSObject.__init__(self, id, filepath, fullname, properties) def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" # I guess it's bad to 'reach inside' ourselves like this, # but Z SQL Methods don't have accessor methdods ;-) s = SQL(self.id, self.title, self.connection_id, self.arguments_src, self.src) s.manage_advanced(self.max_rows_, self.max_cache_, self.cache_time_, self.class_name_, self.class_file_, connection_hook=self.connection_hook, direct=self.allow_simple_one_argument_traversal) return s def _readFile(self, reparse): """Read the data from the filesystem. """ file = open(self._filepath, 'r') # not 'rb', as this is a text file! try: data = file.read() finally: file.close() # parse parameters parameters = {} start = data.find('<dtml-comment>') end = data.find('</dtml-comment>') if start == -1 or end == -1 or start > end: raise ValueError, 'Could not find parameter block' block = data[start + 14:end] for line in block.split('\n'): pair = line.split(':', 1) if len(pair) != 2: continue parameters[pair[0].strip().lower()] = pair[1].strip() # check for required parameters try: connection_id = (parameters.get('connection id', '') or parameters['connection_id']) except KeyError, e: raise ValueError("The '%s' parameter is required " "but was not supplied" % e) # Optional parameters title = parameters.get('title', '') arguments = parameters.get('arguments', '') max_rows = parameters.get('max_rows', 1000) max_cache = parameters.get('max_cache', 100) cache_time = parameters.get('cache_time', 0) class_name = parameters.get('class_name', '') class_file = parameters.get('class_file', '') connection_hook = parameters.get('connection_hook', None) direct = parameters.get('allow_simple_one_argument_traversal', None) self.manage_edit(title, connection_id, arguments, template=data) self.manage_advanced(max_rows, max_cache, cache_time, class_name, class_file, connection_hook=connection_hook, direct=direct)
class FSDTMLMethod(RestrictedDTML, RoleManager, FSObject, Globals.HTML): """FSDTMLMethods act like DTML methods but are not directly modifiable from the management interface.""" meta_type = 'Filesystem DTML Method' manage_options = (( { 'label': 'Customize', 'action': 'manage_main' }, { 'label': 'View', 'action': '', 'help': ('OFSP', 'DTML-DocumentOrMethod_View.stx') }, { 'label': 'Proxy', 'action': 'manage_proxyForm', 'help': ('OFSP', 'DTML-DocumentOrMethod_Proxy.stx') }, ) + Cacheable.manage_options) _proxy_roles = () _cache_namespace_keys = () # Use declarative security security = ClassSecurityInfo() security.declareObjectProtected(View) security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = Globals.DTMLFile('custdtml', _dtmldir) _reading = 0 def __init__(self, id, filepath, fullname=None, properties=None): FSObject.__init__(self, id, filepath, fullname, properties) # Normally called via HTML.__init__ but we don't need the rest that # happens there. self.initvars(None, {}) def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" return DTMLMethod(self.read(), __name__=self.getId()) def _readFile(self, reparse): fp = expandpath(self._filepath) file = open(fp, 'r') # not 'rb', as this is a text file! try: data = file.read() finally: file.close() self.raw = data if reparse: self._reading = 1 # Avoid infinite recursion try: self.cook() finally: self._reading = 0 # Hook up chances to reload in debug mode security.declarePrivate('read_raw') def read_raw(self): if not self._reading: self._updateFromFS() return Globals.HTML.read_raw(self) #### The following is mainly taken from OFS/DTMLMethod.py ### index_html = None # Prevent accidental acquisition # Documents masquerade as functions: func_code = DTMLMethod.func_code default_content_type = 'text/html' def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw): """Render the document given a client object, REQUEST mapping, Response, and key word arguments.""" self._updateFromFS() if not self._cache_namespace_keys: data = self.ZCacheable_get(default=_marker) if data is not _marker: # Return cached results. return data kw['document_id'] = self.getId() kw['document_title'] = self.title security = getSecurityManager() security.addContext(self) try: if client is None: # Called as subtemplate, so don't need error propagation! r = Globals.HTML.__call__(self, client, REQUEST, **kw) if RESPONSE is None: result = r else: result = decapitate(r, RESPONSE) if not self._cache_namespace_keys: self.ZCacheable_set(result) return result r = Globals.HTML.__call__(self, client, REQUEST, **kw) if type(r) is not type('') or RESPONSE is None: if not self._cache_namespace_keys: self.ZCacheable_set(r) return r finally: security.removeContext(self) have_key = RESPONSE.headers.has_key if not (have_key('content-type') or have_key('Content-Type')): if self.__dict__.has_key('content_type'): c = self.content_type else: c, e = guess_content_type(self.getId(), r) RESPONSE.setHeader('Content-Type', c) result = decapitate(r, RESPONSE) if not self._cache_namespace_keys: self.ZCacheable_set(result) return result def getCacheNamespaceKeys(self): ''' Returns the cacheNamespaceKeys. ''' return self._cache_namespace_keys def setCacheNamespaceKeys(self, keys, REQUEST=None): ''' Sets the list of names that should be looked up in the namespace to provide a cache key. ''' ks = [] for key in keys: key = strip(str(key)) if key: ks.append(key) self._cache_namespace_keys = tuple(ks) if REQUEST is not None: return self.ZCacheable_manage(self, REQUEST) # Zope 2.3.x way: def validate(self, inst, parent, name, value, md=None): return getSecurityManager().validate(inst, parent, name, value) security.declareProtected(FTPAccess, 'manage_FTPget') manage_FTPget = DTMLMethod.manage_FTPget security.declareProtected(ViewManagementScreens, 'PrincipiaSearchSource') PrincipiaSearchSource = DTMLMethod.PrincipiaSearchSource security.declareProtected(ViewManagementScreens, 'document_src') document_src = DTMLMethod.document_src security.declareProtected(ViewManagementScreens, 'manage_haveProxy') manage_haveProxy = DTMLMethod.manage_haveProxy
class FSImage(FSObject): """FSImages act like images but are not directly modifiable from the management interface.""" # Note that OFS.Image.Image is not a base class because it is mutable. meta_type = 'Filesystem Image' _data = None manage_options = ({ 'label': 'Customize', 'action': 'manage_main' }, ) + Cacheable.manage_options security = ClassSecurityInfo() security.declareObjectProtected(View) def __init__(self, id, filepath, fullname=None, properties=None): id = fullname or id # Use the whole filename. FSObject.__init__(self, id, filepath, fullname, properties) security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = Globals.DTMLFile('custimage', _dtmldir) content_type = 'unknown/unknown' def _createZODBClone(self): return Image(self.getId(), '', self._readFile(1)) def _readFile(self, reparse): fp = expandpath(self._filepath) file = open(fp, 'rb') try: data = self._data = file.read() finally: file.close() if reparse or self.content_type == 'unknown/unknown': self.ZCacheable_invalidate() ct, width, height = getImageInfo(data) self.content_type = ct self.width = width self.height = height return data #### The following is mainly taken from OFS/Image.py ### __str__ = Image.__str__.im_func _image_tag = Image.tag security.declareProtected(View, 'tag') def tag(self, *args, **kw): # Hook into an opportunity to reload metadata. self._updateFromFS() return self._image_tag(*args, **kw) security.declareProtected(View, 'index_html') def index_html(self, REQUEST, RESPONSE): """ The default view of the contents of a File or Image. Returns the contents of the file or image. Also, sets the Content-Type HTTP header to the objects content type. """ self._updateFromFS() data = self._data # HTTP If-Modified-Since header handling. header = REQUEST.get_header('If-Modified-Since', None) if header is not None: header = string.split(header, ';')[0] # Some proxies seem to send invalid date strings for this # header. If the date string is not valid, we ignore it # rather than raise an error to be generally consistent # with common servers such as Apache (which can usually # understand the screwy date string as a lucky side effect # of the way they parse it). try: mod_since = long(DateTime(header).timeTime()) except: mod_since = None if mod_since is not None: last_mod = self._file_mod_time if last_mod > 0 and last_mod <= mod_since: # Set header values since apache caching will return # Content-Length of 0 in response if size is not set here RESPONSE.setHeader('Last-Modified', rfc1123_date(last_mod)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', len(data)) RESPONSE.setStatus(304) return '' #Last-Modified will get stomped on by a cache policy it there is one set.... RESPONSE.setHeader('Last-Modified', rfc1123_date(self._file_mod_time)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', len(data)) #There are 2 Cache Managers which can be in play....need to decide which to use #to determine where the cache headers are decided on. if self.ZCacheable_getManager() is not None: self.ZCacheable_set(None) else: _setCacheHeaders(_ViewEmulator().__of__(self), extra_context={}) return data security.declareProtected(View, 'getContentType') def getContentType(self): """Get the content type of a file or image. Returns the content type (MIME type) of a file or image. """ self._updateFromFS() return self.content_type security.declareProtected(View, 'get_size') def get_size(self): """ Return the size of the image. """ self._updateFromFS() return self._data and len(self._data) or 0 security.declareProtected(FTPAccess, 'manage_FTPget') manage_FTPget = index_html
class BrowserIdManager(Item, Persistent, Implicit, RoleManager, Owned, Tabs): """ browser id management class """ meta_type = 'Browser Id Manager' manage_options = ({ 'label': 'Settings', 'action': 'manage_browseridmgr', }, { 'label': 'Security', 'action': 'manage_access' }, { 'label': 'Ownership', 'action': 'manage_owner' }) __implements__ = (SessionInterfaces.BrowserIdManagerInterface, ) icon = 'misc_/Sessions/idmgr.gif' security = ClassSecurityInfo() security.declareObjectPublic() ok = { 'meta_type': 1, 'id': 1, 'title': 1, 'icon': 1, 'bobobase_modification_time': 1, 'title_or_id': 1 } security.setDefaultAccess(ok) security.setPermissionDefault(MGMT_SCREEN_PERM, ['Manager']) security.setPermissionDefault(ACCESS_CONTENTS_PERM, ['Manager', 'Anonymous']) security.setPermissionDefault(CHANGE_IDMGR_PERM, ['Manager']) # backwards-compatibility for pre-2.6 instances auto_url_encoding = 0 def __init__(self, id, title='', idname='_ZopeId', location=('cookies', 'form'), cookiepath=('/'), cookiedomain='', cookielifedays=0, cookiesecure=0, auto_url_encoding=0): self.id = str(id) self.title = str(title) self.setBrowserIdName(idname) self.setBrowserIdNamespaces(location) self.setCookiePath(cookiepath) self.setCookieDomain(cookiedomain) self.setCookieLifeDays(cookielifedays) self.setCookieSecure(cookiesecure) self.setAutoUrlEncoding(auto_url_encoding) def manage_afterAdd(self, item, container): """ Maybe add our traversal hook """ self.updateTraversalData() def manage_beforeDelete(self, item, container): """ Remove our traversal hook if it exists """ self.unregisterTraversalHook() security.declareProtected(ACCESS_CONTENTS_PERM, 'hasBrowserId') def hasBrowserId(self): """ Returns true if there is a current browser id, but does not create a browser id for the current request if one doesn't already exist """ if self.getBrowserId(create=0): return 1 security.declareProtected(ACCESS_CONTENTS_PERM, 'getBrowserId') def getBrowserId(self, create=1): """ Examines the request and hands back browser id value or None if no id exists. If there is no browser id and if 'create' is true, create one. If cookies are are an allowable id namespace and create is true, set one. Stuff the id and the namespace it was found in into the REQUEST object for further reference during this request. """ REQUEST = self.REQUEST # let's see if bid has already been attached to request bid = getattr(REQUEST, 'browser_id_', None) if bid is not None: # it's already set in this request so we can just return it # if it's well-formed if not isAWellFormedBrowserId(bid): # somebody screwed with the REQUEST instance during # this request. raise BrowserIdManagerErr, ( 'Ill-formed browserid in REQUEST.browser_id_: %s' % escape(bid)) return bid # fall through & ck form/cookie namespaces if bid is not in request. tk = self.browserid_name ns = self.browserid_namespaces for name in ns: if name == 'url': continue # browser ids in url are checked by Traverser class current_ns = getattr(REQUEST, name, None) if current_ns is None: continue bid = current_ns.get(tk, None) if bid is not None: # hey, we got a browser id! if isAWellFormedBrowserId(bid): # bid is not "plain old broken" REQUEST.browser_id_ = bid REQUEST.browser_id_ns_ = name return bid # fall through if bid is invalid or not in namespaces if create: # create a brand new bid bid = getNewBrowserId() if 'cookies' in ns: self._setCookie(bid, REQUEST) REQUEST.browser_id_ = bid REQUEST.browser_id_ns_ = None return bid # implies a return of None if: # (not create=1) and (invalid or ((not in req) and (not in ns))) security.declareProtected(ACCESS_CONTENTS_PERM, 'flushBrowserIdCookie') def flushBrowserIdCookie(self): """ removes the bid cookie from the client browser """ if 'cookies' not in self.browserid_namespaces: raise BrowserIdManagerErr, ('Cookies are not now being used as a ' 'browser id namespace, thus the ' 'browserid cookie cannot be flushed.') self._setCookie('deleted', self.REQUEST, remove=1) security.declareProtected(ACCESS_CONTENTS_PERM, 'setBrowserIdCookieByForce') def setBrowserIdCookieByForce(self, bid): """ """ if 'cookies' not in self.browserid_namespaces: raise BrowserIdManagerErr, ('Cookies are not now being used as a ' 'browser id namespace, thus the ' 'browserid cookie cannot be forced.') self._setCookie(bid, self.REQUEST) security.declareProtected(ACCESS_CONTENTS_PERM, 'isBrowserIdFromCookie') def isBrowserIdFromCookie(self): """ returns true if browser id is from REQUEST.cookies """ if not self.getBrowserId(): # make sure the bid is stuck on REQUEST raise BrowserIdManagerErr, 'There is no current browser id.' if getattr(self.REQUEST, 'browser_id_ns_') == 'cookies': return 1 security.declareProtected(ACCESS_CONTENTS_PERM, 'isBrowserIdFromForm') def isBrowserIdFromForm(self): """ returns true if browser id is from REQUEST.form """ if not self.getBrowserId(): # make sure the bid is stuck on REQUEST raise BrowserIdManagerErr, 'There is no current browser id.' if getattr(self.REQUEST, 'browser_id_ns_') == 'form': return 1 security.declareProtected(ACCESS_CONTENTS_PERM, 'isBrowserIdFromUrl') def isBrowserIdFromUrl(self): """ returns true if browser id is from first element of the URL """ if not self.getBrowserId(): # make sure the bid is stuck on REQUEST raise BrowserIdManagerErr, 'There is no current browser id.' if getattr(self.REQUEST, 'browser_id_ns_') == 'url': return 1 security.declareProtected(ACCESS_CONTENTS_PERM, 'isBrowserIdNew') def isBrowserIdNew(self): """ returns true if browser id is 'new', meaning the id exists but it has not yet been acknowledged by the client (the client hasn't sent it back to us in a cookie or in a formvar). """ if not self.getBrowserId(): # make sure the id is stuck on REQUEST raise BrowserIdManagerErr, 'There is no current browser id.' # ns will be None if new, negating None below returns 1, which # would indicate that it's new on this request return getattr(self.REQUEST, 'browser_id_ns_', None) == None security.declareProtected(ACCESS_CONTENTS_PERM, 'encodeUrl') def encodeUrl(self, url, style='querystring', create=1): """ encode a URL with the browser id as a postfixed query string element or inlined into the url depending on the 'style' parameter """ bid = self.getBrowserId(create) if bid is None: raise BrowserIdManagerErr, 'There is no current browser id.' name = self.getBrowserIdName() if style == 'querystring': # encode bid in querystring if '?' in url: return '%s&%s=%s' % (url, name, bid) else: return '%s?%s=%s' % (url, name, bid) else: # encode bid as first two URL path segments proto, host, path, params, query, frag = urlparse(url) path = '/%s/%s%s' % (name, bid, path) return urlunparse((proto, host, path, params, query, frag)) security.declareProtected(MGMT_SCREEN_PERM, 'manage_browseridmgr') manage_browseridmgr = Globals.DTMLFile('dtml/manageIdManager', globals()) security.declareProtected(CHANGE_IDMGR_PERM, 'manage_changeBrowserIdManager') def manage_changeBrowserIdManager(self, title='', idname='_ZopeId', location=('cookies', 'form'), cookiepath='/', cookiedomain='', cookielifedays=0, cookiesecure=0, auto_url_encoding=0, REQUEST=None): """ """ self.title = str(title) self.setBrowserIdName(idname) self.setCookiePath(cookiepath) self.setCookieDomain(cookiedomain) self.setCookieLifeDays(cookielifedays) self.setCookieSecure(cookiesecure) self.setBrowserIdNamespaces(location) self.setAutoUrlEncoding(auto_url_encoding) self.updateTraversalData() if REQUEST is not None: msg = '/manage_browseridmgr?manage_tabs_message=Changes saved' REQUEST.RESPONSE.redirect(self.absolute_url() + msg) security.declareProtected(CHANGE_IDMGR_PERM, 'setBrowserIdName') def setBrowserIdName(self, k): """ sets browser id name string """ if not (type(k) is type('') and k and not badidnamecharsin(k)): raise BrowserIdManagerErr, 'Bad id name string %s' % escape( repr(k)) self.browserid_name = k security.declareProtected(ACCESS_CONTENTS_PERM, 'getBrowserIdName') def getBrowserIdName(self): """ """ return self.browserid_name security.declareProtected(CHANGE_IDMGR_PERM, 'setBrowserIdNamespaces') def setBrowserIdNamespaces(self, ns): """ accepts list of allowable browser id namespaces """ for name in ns: if name not in ALLOWED_BID_NAMESPACES: raise BrowserIdManagerErr, ('Bad browser id namespace %s' % repr(name)) self.browserid_namespaces = tuple(ns) security.declareProtected(ACCESS_CONTENTS_PERM, 'getBrowserIdNamespaces') def getBrowserIdNamespaces(self): """ """ return self.browserid_namespaces security.declareProtected(CHANGE_IDMGR_PERM, 'setCookiePath') def setCookiePath(self, path=''): """ sets cookie 'path' element for id cookie """ if not (type(path) is type('') and not badcookiecharsin(path)): raise BrowserIdManagerErr, 'Bad cookie path %s' % escape( repr(path)) self.cookie_path = path security.declareProtected(ACCESS_CONTENTS_PERM, 'getCookiePath') def getCookiePath(self): """ """ return self.cookie_path security.declareProtected(CHANGE_IDMGR_PERM, 'setCookieLifeDays') def setCookieLifeDays(self, days): """ offset for id cookie 'expires' element """ if type(days) not in (type(1), type(1.0)): raise BrowserIdManagerErr, ( 'Bad cookie lifetime in days %s (requires integer value)' % escape(repr(days))) self.cookie_life_days = int(days) security.declareProtected(ACCESS_CONTENTS_PERM, 'getCookieLifeDays') def getCookieLifeDays(self): """ """ return self.cookie_life_days security.declareProtected(CHANGE_IDMGR_PERM, 'setCookieDomain') def setCookieDomain(self, domain): """ sets cookie 'domain' element for id cookie """ if type(domain) is not type(''): raise BrowserIdManagerErr, ('Cookie domain must be string: %s' % escape(repr(domain))) if not domain: self.cookie_domain = '' return if not twodotsin(domain): raise BrowserIdManagerErr, ( 'Cookie domain must contain at least two dots (e.g. ' '".zope.org" or "www.zope.org") or it must be left blank. : ' '%s' % escape( ` domain `)) if badcookiecharsin(domain): raise BrowserIdManagerErr, ('Bad characters in cookie domain %s' % escape( ` domain `)) self.cookie_domain = domain security.declareProtected(ACCESS_CONTENTS_PERM, 'getCookieDomain') def getCookieDomain(self): """ """ return self.cookie_domain security.declareProtected(CHANGE_IDMGR_PERM, 'setCookieSecure') def setCookieSecure(self, secure): """ sets cookie 'secure' element for id cookie """ self.cookie_secure = not not secure security.declareProtected(ACCESS_CONTENTS_PERM, 'getCookieSecure') def getCookieSecure(self): """ """ return self.cookie_secure security.declareProtected(CHANGE_IDMGR_PERM, 'setCookieSecure') def setAutoUrlEncoding(self, auto_url_encoding): """ sets 'auto url encoding' on or off """ self.auto_url_encoding = not not auto_url_encoding security.declareProtected(ACCESS_CONTENTS_PERM, 'getAutoUrlEncoding') def getAutoUrlEncoding(self): """ """ return self.auto_url_encoding security.declareProtected(ACCESS_CONTENTS_PERM, 'isUrlInBidNamespaces') def isUrlInBidNamespaces(self): """ Returns true if 'url' is in the browser id namespaces for this browser id """ return 'url' in self.browserid_namespaces security.declareProtected(ACCESS_CONTENTS_PERM, 'getHiddenFormField') def getHiddenFormField(self): """ Convenience method which returns a hidden form element representing the current browser id name and browser id """ s = '<input type="hidden" name="%s" value="%s">' return s % (self.getBrowserIdName(), self.getBrowserId()) def _setCookie(self, bid, REQUEST, remove=0, now=time.time, strftime=time.strftime, gmtime=time.gmtime): """ """ expires = None if remove: expires = "Sun, 10-May-1971 11:59:00 GMT" elif self.cookie_life_days: expires = now() + self.cookie_life_days * 86400 # Wdy, DD-Mon-YYYY HH:MM:SS GMT expires = strftime('%a %d-%b-%Y %H:%M:%S GMT', gmtime(expires)) d = { 'domain': self.cookie_domain, 'path': self.cookie_path, 'secure': self.cookie_secure, 'expires': expires } if self.cookie_secure: URL1 = REQUEST.get('URL1', None) if URL1 is None: return # should we raise an exception? if string.split(URL1, ':')[0] != 'https': return # should we raise an exception? cookies = REQUEST.RESPONSE.cookies cookie = cookies[self.browserid_name] = {} for k, v in d.items(): if v: cookie[k] = v #only stuff things with true values cookie['value'] = bid def _setId(self, id): if id != self.id: raise Globals.MessageDialog( title='Cannot rename', message='You cannot rename a browser id manager, sorry!', action='./manage_main', ) def updateTraversalData(self): if self.isUrlInBidNamespaces(): self.registerTraversalHook() else: self.unregisterTraversalHook() def unregisterTraversalHook(self): parent = aq_parent(aq_inner(self)) name = TRAVERSAL_APPHANDLE if self.hasTraversalHook(parent): unregisterBeforeTraverse(parent, name) def registerTraversalHook(self): parent = aq_parent(aq_inner(self)) if not self.hasTraversalHook(parent): hook = BrowserIdManagerTraverser() name = TRAVERSAL_APPHANDLE priority = 40 # "higher" priority than session data traverser registerBeforeTraverse(parent, hook, name, priority) def hasTraversalHook(self, parent): name = TRAVERSAL_APPHANDLE return not not queryBeforeTraverse(parent, name)
from urllib import quote from urlparse import urlparse, urlunparse from ZPublisher.BeforeTraverse import registerBeforeTraverse, \ unregisterBeforeTraverse, queryBeforeTraverse import logging b64_trans = string.maketrans('+/', '-.') b64_untrans = string.maketrans('-.', '+/') badidnamecharsin = re.compile('[\?&;,<> ]').search badcookiecharsin = re.compile('[;,<>& ]').search twodotsin = re.compile('(\w*\.){2,}').search _marker = [] constructBrowserIdManagerForm = Globals.DTMLFile('dtml/addIdManager', globals()) BROWSERID_MANAGER_NAME = 'browser_id_manager' # imported by SessionDataManager ALLOWED_BID_NAMESPACES = ('form', 'cookies', 'url') ADD_BROWSER_ID_MANAGER_PERM = "Add Browser Id Manager" TRAVERSAL_APPHANDLE = 'BrowserIdManager' LOG = logging.getLogger('Zope.BrowserIdManager') def constructBrowserIdManager(self, id=BROWSERID_MANAGER_NAME, title='', idname='_ZopeId', location=('cookies', 'form'), cookiepath='/',