def createNewUserIfNotExists(): """ Create a new Admin user, if the userDB is empty """ userMod = getattr(conf["viur.mainApp"], "user", None) if (userMod # We have a user module and isinstance(userMod, User) and "addSkel" in dir(userMod) and "validAuthenticationMethods" in dir( userMod) # Its our user module :) and any([ issubclass(x[0], UserPassword) for x in userMod.validAuthenticationMethods ])): # It uses UserPassword login if not db.Query(userMod.addSkel().kindName).getEntry( ): # There's currently no user in the database addSkel = skeletonByKind(userMod.addSkel().kindName)( ) # Ensure we have the full skeleton uname = "admin@%s.appspot.com" % utils.projectID pw = utils.generateRandomString(13) addSkel["name"] = uname addSkel["status"] = 10 # Ensure its enabled right away addSkel["access"] = ["root"] addSkel["password"] = pw try: addSkel.toDB() except Exception as e: logging.error( "Something went wrong when trying to add admin user %s with Password %s", uname, pw) logging.exception(e) return logging.warning( "ViUR created a new admin-user for you! Username: %s, Password: %s", uname, pw) email.sendEMailToAdmins( "Your new ViUR password", "ViUR created a new admin-user for you! Username: %s, Password: %s" % (uname, pw))
def exportItems(module, target, importKey, startCursor, endCursor): Skel = skeletonByKind(module) query = Skel().all().cursor(startCursor, endCursor) for item in query.run(250): flatItem = DbTransfer.genDict(item) formFields = { "e": pickle.dumps(flatItem).encode("HEX"), "key": importKey } result = urlfetch.fetch( url=target, payload=urllib.urlencode(formFields), method=urlfetch.POST, headers={'Content-Type': 'application/x-www-form-urlencoded'}) if startCursor == endCursor: try: email.sendEMailToAdmins( "Export of kind %s finished" % module, "ViUR finished to export kind %s to %s.\n" % (module, target)) except: # OverQuota, whatever pass
def deferred(self, *args, **kwargs): """ This catches one deferred call and routes it to its destination """ global _deferedTasks, _appengineServiceIPs req = currentRequest.get().request if 'X-AppEngine-TaskName' not in req.headers: logging.critical( 'Detected an attempted XSRF attack. The header "X-AppEngine-Taskname" was not set.' ) raise errors.Forbidden() if req.environ.get("HTTP_X_APPENGINE_USER_IP") not in _appengineServiceIPs \ and (not utils.isLocalDevelopmentServer or os.getenv("TASKS_EMULATOR") is None): logging.critical( 'Detected an attempted XSRF attack. This request did not originate from Task Queue.' ) raise errors.Forbidden() # Check if the retry count exceeds our warning threshold retryCount = req.headers.get("X-Appengine-Taskretrycount", None) if retryCount: if int(retryCount) == self.retryCountWarningThreshold: from viur.core import email email.sendEMailToAdmins( "Deferred task retry count exceeded warning threshold", "Task %s will now be retried for the %sth time." % (req.headers.get("X-Appengine-Taskname", ""), retryCount)) cmd, data = json.loads(req.body, object_hook=jsonDecodeObjectHook) funcPath, args, kwargs, env = data if env: if "user" in env and env["user"]: currentSession.get()["user"] = env["user"] if "lang" in env and env["lang"]: currentLanguage.set(env["lang"]) if "transactionMarker" in env: marker = db.Get( db.Key("viur-transactionmarker", env["transactionMarker"])) if not marker: logging.info( "Dropping task, transaction %s did not apply" % env["transactionMarker"]) return else: logging.info("Executing task, transaction %s did succeed" % env["transactionMarker"]) if "custom" in env and conf["viur.tasks.customEnvironmentHandler"]: # Check if we need to restore additional environmental data assert isinstance(conf["viur.tasks.customEnvironmentHandler"], tuple) \ and len(conf["viur.tasks.customEnvironmentHandler"]) == 2 \ and callable(conf["viur.tasks.customEnvironmentHandler"][1]), \ "Your customEnvironmentHandler must be a tuple of two callable if set!" conf["viur.tasks.customEnvironmentHandler"][1](env["custom"]) if cmd == "rel": caller = conf["viur.mainApp"] pathlist = [x for x in funcPath.split("/") if x] for currpath in pathlist: if currpath not in dir(caller): logging.error( "ViUR missed a deferred task! Could not resolve the path %s. " "Failed segment was %s", funcPath, currpath) return caller = getattr(caller, currpath) try: caller(*args, **kwargs) except PermanentTaskFailure: pass except Exception as e: logging.exception(e) raise errors.RequestTimeout() # Task-API should retry elif cmd == "unb": if not funcPath in _deferedTasks: logging.error("ViUR missed a deferred task! %s(%s,%s)", funcPath, args, kwargs) # We call the deferred function *directly* (without walking through the mkDeferred lambda), so ensure # that any hit to another deferred function will defer again req.DEFERED_TASK_CALLED = True try: _deferedTasks[funcPath](*args, **kwargs) except PermanentTaskFailure: pass except Exception as e: logging.exception(e) raise errors.RequestTimeout() # Task-API should retry
def iterImport(module, target, exportKey, cursor=None, amount=0): """ Processes 100 Entries and calls the next batch """ urlfetch.set_default_fetch_deadline(20) payload = {"module": module, "key": exportKey} if cursor: payload.update({"cursor": cursor}) result = urlfetch.fetch( url=target, payload=urllib.urlencode(payload), method=urlfetch.POST, headers={'Content-Type': 'application/x-www-form-urlencoded'}) if result.status_code == 200: res = pickle.loads(result.content.decode("HEX")) skel = skeletonByKind(module)() logging.info("%s: %d new entries fetched, total %d entries fetched" % (module, len(res["values"]), amount)) if len(res["values"]) == 0: try: email.sendEMailToAdmins( "Import of kind %s finished with %d entities" % (module, amount), "ViUR finished to import %d entities of " "kind %s from %s.\n" % (amount, module, target)) except: # OverQuota, whatever logging.error("Unable to send Email") return for entry in res["values"]: for k in list(entry.keys())[:]: if isinstance(entry[k], str): entry[k] = entry[k].decode("UTF-8") if not "key" in entry: entry["key"] = entry["id"] key = db.Key(encoded=utils.normalizeKey(entry["key"])) # Special case: Convert old module root nodes!!! if module.endswith( "_rootNode") and key.name() and "_modul_" in key.name(): name = key.name().replace("_modul_", "_module_") else: name = key.name() dbEntry = db.Entity(kind=key.kind(), parent=key.parent(), id=key.id(), name=name) for k in entry.keys(): if k == "key": continue dbEntry[k] = entry[k] # Special case: Convert old module root nodes!!! if (isinstance(skel, (HierarchySkel, TreeLeafSkel)) and k in ["parentdir", "parententry", "parentrepo"] and entry[k]): key = db.Key(encoded=str(entry[k])) if key.parent(): parent = db.Key( encoded=utils.normalizeKey(key.parent())) else: parent = None if key.id_or_name() and "_modul_" in str(key.id_or_name()): name = key.id_or_name().replace("_modul_", "_module_") else: name = key.id_or_name() dbEntry[k] = str( db.Key.from_path(key.kind(), name, parent=parent)) db.Put(dbEntry) skel.fromDB(str(dbEntry.key())) skel.refresh() skel.toDB(clearUpdateTag=True) amount += 1 iterImport(module, target, exportKey, res["cursor"], amount)
def buildApp(modules: Union[ModuleType, object], renderers: Union[ModuleType, Dict], default: str = None): """ Creates the application-context for the current instance. This function converts the classes found in the *modules*-module, and the given renders into the object found at ``conf["viur.mainApp"]``. Every class found in *modules* becomes - instanced - get the corresponding renderer attached - will be attached to ``conf["viur.mainApp"]`` :param modules: Usually the module provided as *modules* directory within the application. :param renderers: Usually the module *server.renders*, or a dictionary renderName => renderClass. :param default: Name of the renderer, which will form the root of the application. This will be the renderer, which wont get a prefix, usually html. (=> /user instead of /html/user) """ class ExtendableObject(object): pass if not isinstance(renderers, dict): # build up the dict from viur.core.render renderers, renderRootModule = {}, renderers for key, renderModule in vars(renderRootModule).items(): if "__" not in key: renderers[key] = {} for subkey, render in vars(renderModule).items(): if "__" not in subkey: renderers[key][subkey] = render del renderRootModule from viur.core.prototypes import BasicApplication # avoid circular import if hasattr(modules, "index"): if issubclass(modules.index, BasicApplication): root = modules.index("index", "") else: root = modules.index() # old style for backward compatibility else: root = ExtendableObject() modules._tasks = TaskHandler resolverDict = {} for moduleName, moduleClass in vars(modules).items(): # iterate over all modules if moduleName == "index": mapModule(root, "index", resolverDict) if isinstance(root, BasicApplication): root.render = renderers[default]["default"](parent=root) continue for renderName, render in renderers.items(): # look, if a particular render should be built if getattr(moduleClass, renderName, False) is True: modulePath = "%s/%s" % ("/" + renderName if renderName != default else "", moduleName) moduleInstance = moduleClass(moduleName, modulePath) # Attach the module-specific or the default render moduleInstance.render = render.get(moduleName, render["default"])(parent=moduleInstance) if renderName == default: # default or render (sub)namespace? setattr(root, moduleName, moduleInstance) targetResolverRender = resolverDict else: if getattr(root, renderName, True) is True: # Render is not build yet, or it is just the simple marker that a given render should be build setattr(root, renderName, ExtendableObject()) # Attach the module to the given renderer node setattr(getattr(root, renderName), moduleName, moduleInstance) targetResolverRender = resolverDict.setdefault(renderName, {}) mapModule(moduleInstance, moduleName, targetResolverRender) # Apply Renderers postProcess Filters if "_postProcessAppObj" in render: render["_postProcessAppObj"](targetResolverRender) if hasattr(moduleClass, "seoLanguageMap"): conf["viur.languageModuleMap"][moduleName] = moduleClass.seoLanguageMap conf["viur.mainResolver"] = resolverDict if conf["viur.exportPassword"] is not None or conf["viur.importPassword"] is not None: # Enable the Database ex/import API from viur.core.dbtransfer import DbTransfer if conf["viur.importPassword"]: logging.critical("The Import-API is enabled! Never do this on production systems!") from viur.core import email try: email.sendEMailToAdmins("Active Database import API", "ViUR just started a new Instance with an ENABLED DATABASE IMPORT API! You have been warned.") except: # OverQuota, whatever pass # Dont render this instance unusable elif conf["viur.exportPassword"]: logging.warning("The Export-API is enabled. Everyone having that key can read the whole database!") setattr(root, "dbtransfer", DbTransfer()) mapModule(root.dbtransfer, "dbtransfer", resolverDict) if conf["viur.debug.traceExternalCallRouting"] or conf["viur.debug.traceInternalCallRouting"]: from viur.core import email try: email.sendEMailToAdmins("Debug mode enabled", "ViUR just started a new Instance with calltracing enabled! This will log sensitive information!") except: # OverQuota, whatever pass # Dont render this instance unusable if default in renderers and hasattr(renderers[default]["default"], "renderEmail"): conf["viur.emailRenderer"] = renderers[default]["default"]().renderEmail elif "html" in renderers: conf["viur.emailRenderer"] = renderers["html"]["default"]().renderEmail return root