def traverse(self, name): if name in self.stepto_utilities: return getUtility(self.stepto_utilities[name]) if name == '~': person = getUtility(ILaunchBag).user if person is None: raise Unauthorized() # Keep the context and the subtree so that # bugs.l.n/~/+assignedbugs goes to the person's canonical # assigned list. return self.redirectSubTree( canonical_url(self.context) + "~" + canonical_name(person.name), status=302) elif name.startswith('~'): # Allow traversal to ~foo for People if canonical_name(name) != name: # (for instance, uppercase username?) if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( canonical_url(self.context) + canonical_name(name), status=301) else: person = getUtility(IPersonSet).getByName(name[1:]) if person is None: return person # Check to see if this is a team, and if so, whether the # logged in user is allowed to view the team, by virtue of # team membership or Launchpad administration. if (person.is_team and not check_permission('launchpad.LimitedView', person)): return None # Only admins are permitted to see suspended users. if person.account_status == AccountStatus.SUSPENDED: if not check_permission('launchpad.Moderate', person): raise GoneError( 'User is suspended: %s' % name) if person.account_status == AccountStatus.PLACEHOLDER: if not check_permission('launchpad.Moderate', person): return None return person # Dapper and Edgy shipped with https://launchpad.net/bazaar hard coded # into the Bazaar Launchpad plugin (part of Bazaar core). So in theory # we need to support this URL until 2011 (although I suspect the API # will break much sooner than that) or updates sent to # {dapper,edgy}-updates. Probably all irrelevant, as I suspect the # number of people using the plugin in edgy and dapper is 0. if name == 'bazaar' and IXMLRPCRequest.providedBy(self.request): return getUtility(IBazaarApplication) # account for common typing mistakes if canonical_name(name) != name: if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( (canonical_url(self.context, request=self.request) + canonical_name(name)), status=301) pillar = getUtility(IPillarNameSet).getByName( name, ignore_inactive=False) if pillar is None: return None if IProduct.providedBy(pillar): if not pillar.active: # Emergency brake for public but inactive products: # These products should not be shown to ordinary users. # The root problem is that many views iterate over products, # inactive products included, and access attributes like # name, displayname or call canonical_url(product) -- # and finally throw the data away, if the product is # inactive. So we cannot make these attributes inaccessible # for inactive public products. On the other hand, we # require the permission launchpad.View to protect private # products. # This means that we cannot simply check if the current # user has the permission launchpad.View for an inactive # product. user = getUtility(ILaunchBag).user if user is None: return None user = IPersonRoles(user) if (not user.in_commercial_admin and not user.in_admin and not user.in_registry_experts): return None if check_permission('launchpad.LimitedView', pillar): if pillar.name != name: # This pillar was accessed through one of its aliases, so we # must redirect to its canonical URL. return self.redirectSubTree( canonical_url(pillar, self.request), status=301) return pillar return None
def attach_http_request(report, context): """Add request metadata into the error report. This reads the exc_info and http_request keys from the context and will write to: * url * ignore * username * topic * req_vars """ info = context.get('exc_info') request = context.get('http_request') if request is None: return # XXX jamesh 2005-11-22: Temporary fix, which Steve should # undo. URL is just too HTTPRequest-specific. if safe_hasattr(request, 'URL'): # URL's are byte strings, but possibly str() will fail - safe_unicode # handles all those cases, and then we can safely encode it to utf8. # This is strictly double handling as a URL should never have unicode # characters in it anyway (though it may have them % encoded, which is # fine). Better safe than sorry, and the safe_unicode handling won't # cause double-encoding, so it is safe. url = oops.createhooks.safe_unicode(request.URL).encode('utf8') report['url'] = url if WebServiceLayer.providedBy(request) and info is not None: webservice_error = getattr( info[1], '__lazr_webservice_error__', 500) if webservice_error / 100 != 5: request.oopsid = None # Tell the oops machinery to ignore this error report['ignore'] = True missing = object() principal = getattr(request, 'principal', missing) if safe_hasattr(principal, 'getLogin'): login = principal.getLogin() elif principal is missing or principal is None: # Request has no principal (e.g. scriptrequest) login = None else: # Request has an UnauthenticatedPrincipal. login = '******' if _get_type(report) in ( _ignored_exceptions_for_unauthenticated_users): report['ignore'] = True if principal is not None and principal is not missing: username = '******'.join([ unicode(login), unicode(request.principal.id), unicode(request.principal.title), unicode(request.principal.description)]) report['username'] = username if getattr(request, '_orig_env', None): report['topic'] = request._orig_env.get('launchpad.pageid', '') for key, value in request.items(): if _is_sensitive(request, key): value = '<hidden>' if not isinstance(value, basestring): value = oops.createhooks.safe_unicode(value) # keys need to be unicode objects. The form items (a subset of # request.items) are generally just the url query_string url decoded, # which means the keys may be invalid in bson docs (bson requires that # they be unicode). key = oops.createhooks.safe_unicode(key) report['req_vars'][key] = value if IXMLRPCRequest.providedBy(request): args = request.getPositionalArguments() # Request variables are strings: this could move to its own key and be # raw. report['req_vars']['xmlrpc args'] = unicode(args)
def traverse(self, name): if name in self.stepto_utilities: return getUtility(self.stepto_utilities[name]) if name == '~': person = getUtility(ILaunchBag).user if person is None: raise Unauthorized() # Keep the context and the subtree so that # bugs.l.n/~/+assignedbugs goes to the person's canonical # assigned list. return self.redirectSubTree( canonical_url(self.context) + "~" + canonical_name(person.name), status=302) elif name.startswith('~'): # Allow traversal to ~foo for People if canonical_name(name) != name: # (for instance, uppercase username?) if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( canonical_url(self.context) + canonical_name(name), status=301) else: person = getUtility(IPersonSet).getByName(name[1:]) if person is None: return person # Check to see if this is a team, and if so, whether the # logged in user is allowed to view the team, by virtue of # team membership or Launchpad administration. if (person.is_team and not check_permission('launchpad.LimitedView', person)): raise NotFound(self.context, name) # Only admins are permitted to see suspended users. if person.account_status == AccountStatus.SUSPENDED: if not check_permission('launchpad.Moderate', person): raise GoneError( 'User is suspended: %s' % name) return person # Dapper and Edgy shipped with https://launchpad.net/bazaar hard coded # into the Bazaar Launchpad plugin (part of Bazaar core). So in theory # we need to support this URL until 2011 (although I suspect the API # will break much sooner than that) or updates sent to # {dapper,edgy}-updates. Probably all irrelevant, as I suspect the # number of people using the plugin in edgy and dapper is 0. if name == 'bazaar' and IXMLRPCRequest.providedBy(self.request): return getUtility(IBazaarApplication) # account for common typing mistakes if canonical_name(name) != name: if self.request.method == 'POST': raise POSTToNonCanonicalURL return self.redirectSubTree( (canonical_url(self.context, request=self.request) + canonical_name(name)), status=301) pillar = getUtility(IPillarNameSet).getByName( name, ignore_inactive=False) if pillar is None: return None if IProduct.providedBy(pillar): if not pillar.active: # Emergency brake for public but inactive products: # These products should not be shown to ordinary users. # The root problem is that many views iterate over products, # inactive products included, and access attributes like # name, displayname or call canonical_url(product) -- # and finally throw the data away, if the product is # inactive. So we cannot make these attributes inaccessible # for inactive public products. On the other hand, we # require the permission launchpad.View to protect private # products. # This means that we cannot simply check if the current # user has the permission launchpad.View for an inactive # product. user = getUtility(ILaunchBag).user if user is None: return None user = IPersonRoles(user) if (not user.in_commercial_admin and not user.in_admin and not user.in_registry_experts): return None if check_permission('launchpad.LimitedView', pillar): if pillar.name != name: # This pillar was accessed through one of its aliases, so we # must redirect to its canonical URL. return self.redirectSubTree( canonical_url(pillar, self.request), status=301) return pillar return None