예제 #1
0
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))
예제 #2
0
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
예제 #3
0
    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
예제 #4
0
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)
예제 #5
0
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