Exemple #1
0
    def view(self, skelType, key, *args, **kwargs):
        """
		Prepares and renders a single entry for viewing.

		The entry is fetched by its *key* and its *skelType*.
		The function performs several access control checks on the requested entity before it is rendered.

		.. seealso:: :func:`canView`, :func:`onView`

		:returns: The rendered representation of the requested entity.

		:param skelType: May either be "node" or "leaf".
		:type skelType: str
		:param node: URL-safe key of the parent.
		:type node: str

		:raises: :exc:`server.errors.NotAcceptable`, when an incorrect *skelType* is provided.
		:raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		"""
        if not self._checkSkelType(skelType):
            raise errors.NotAcceptable()
        skel = self.viewSkel(skelType)
        if not key:
            raise errors.NotAcceptable()
        # We return a single entry for viewing
        if not skel.fromDB(key):
            raise errors.NotFound()
        if not self.canView(skelType, skel):
            raise errors.Unauthorized()
        self.onView(skel)
        return self.render.view(skel)
Exemple #2
0
    def getBill(self, key, *args, **kwargs):
        """
			Returns the Bill for the given order.
		"""
        skel = self.viewSkel()

        if "canView" in dir(self):
            if not self.canView(key):
                raise errors.Unauthorized()
        else:
            queryObj = self.viewSkel().all().mergeExternalFilter({"key": key})
            queryObj = self.listFilter(queryObj)  # Access control

            if queryObj is None:
                raise errors.Unauthorized()

        bill = self.getBillPdf(key)

        if not bill:
            raise errors.NotFound()

        request.current.get(
        ).response.headers['Content-Type'] = "application/pdf"

        return (bill)
Exemple #3
0
    def view(self, *args, **kwargs):
        """
			Prepares and renders a single entry for viewing.

			The entry is fetched by its entity key, which either is provided via *kwargs["key"]*,
			or as the first parameter in *args*. The function performs several access control checks
			on the requested entity before it is rendered.

			.. seealso:: :func:`viewSkel`, :func:`canView`, :func:`onView`

			:returns: The rendered representation of the requested entity.

			:raises: :exc:`viur.core.errors.NotAcceptable`, when no *key* is provided.
			:raises: :exc:`viur.core.errors.NotFound`, when no entry with the given *key* was found.
			:raises: :exc:`viur.core.errors.Unauthorized`, if the current user does not have the required permissions.
		"""
        if "key" in kwargs:
            key = kwargs["key"]
        elif len(args) >= 1:
            key = args[0]
        else:
            raise errors.NotAcceptable()
        if not key:
            raise errors.NotAcceptable()
        # We return a single entry for viewing
        skel = self.viewSkel()
        if not skel.fromDB(key):
            raise errors.NotFound()
        if not self.canView(skel):
            raise errors.Forbidden()
        self.onView(skel)
        return self.render.view(skel)
Exemple #4
0
    def delete(self, key, skey, *args, **kwargs):
        """
			Delete an entry.

			The function runs several access control checks on the data before it is deleted.

			.. seealso:: :func:`canDelete`, :func:`editSkel`, :func:`onDeleted`

			:returns: The rendered, deleted object of the entry.

			:raises: :exc:`viur.core.errors.NotFound`, when no entry with the given *key* was found.
			:raises: :exc:`viur.core.errors.Unauthorized`, if the current user does not have the required permissions.
			:raises: :exc:`viur.core.errors.PreconditionFailed`, if the *skey* could not be verified.
		"""

        skel = self.editSkel()
        if not skel.fromDB(key):
            raise errors.NotFound()

        if not self.canDelete(skel):
            raise errors.Unauthorized()

        if not securitykey.validate(skey, useSessionKey=True):
            raise errors.PreconditionFailed()

        self.onDelete(skel)
        skel.delete()
        self.onDeleted(skel)

        return self.render.deleteSuccess(skel)
Exemple #5
0
    def list(self, parent, *args, **kwargs):
        """
		List the entries which are direct children of the given *parent*.
		Any other supplied parameters are interpreted as filters for the elements displayed.

		.. seealso:: :func:`canList`, :func:`server.db.mergeExternalFilter`

		:param parent: URL-safe key of the parent.
		:type parent: str

		:returns: The rendered list objects for the matching entries.

		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		:raises: :exc:`server.errors.NotFound`, if *parent* could not be found.
		"""
        if not parent or not self.canList(parent):
            raise errors.Unauthorized()

        parentSkel = self.viewSkel()

        if not parentSkel.fromDB(parent):
            if not str(parent) in [
                    str(x["key"]) for x in self.getAvailableRootNodes()
            ]:
                # It isn't a rootNode either
                raise errors.NotFound()
            else:
                parentSkel = None

        query = self.viewSkel().all()
        query.mergeExternalFilter(kwargs)
        query.filter("parententry", parent)
        return self.render.list(query.fetch(),
                                parent=parent,
                                parentSkel=parentSkel)
    def view(self, *args, **kwargs):
        """
		Prepares and renders the singleton entry for viewing.

		The function performs several access control checks on the requested entity before it is rendered.

		.. seealso:: :func:`viewSkel`, :func:`canView`, :func:`onViewed`

		:returns: The rendered representation of the entity.

		:raises: :exc:`server.errors.NotFound`, if there is no singleton entry existing, yet.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		"""

        skel = self.viewSkel()
        if not self.canView():
            raise errors.Unauthorized()

        key = db.Key(self.editSkel().kindName, self.getKey())

        if not skel.fromDB(key):
            raise errors.NotFound()

        self.onViewed(skel)
        return self.render.view(skel)
Exemple #7
0
    def add(self, skelType, node, *args, **kwargs):
        """
		Add a new entry with the given parent *node*, and render the entry, eventually with error notes
		on incorrect data. Data is taken by any other arguments in *kwargs*.

		The function performs several access control checks on the requested entity before it is added.

		.. seealso:: :func:`onAdded`, :func:`canAdd`

		:param skelType: Defines the type of the new entry and may either be "node" or "leaf".
		:type skelType: str
		:param node: URL-safe key of the parent.
		:type node: str

		:returns: The rendered, added object of the entry, eventually with error hints.

		:raises: :exc:`server.errors.NotAcceptable`, when no valid *skelType* was provided.
		:raises: :exc:`server.errors.NotFound`, when no valid *node* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		:raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified.
		"""
        if "skey" in kwargs:
            skey = kwargs["skey"]
        else:
            skey = ""
        if skelType == "node":
            skelType = TreeType.Node
        elif skelType == "leaf" and self.leafSkelCls:
            skelType = TreeType.Leaf
        else:
            raise errors.NotAcceptable()
        skel = self.addSkel(skelType)
        parentNodeSkel = self.editSkel(TreeType.Node)
        if not parentNodeSkel.fromDB(node):
            raise errors.NotFound()
        if not self.canAdd(skelType, parentNodeSkel):
            raise errors.Unauthorized()
        if (len(kwargs) == 0  # no data supplied
                or skey == ""  # no security key
                or not skel.fromClient(
                    kwargs)  # failure on reading into the bones
                or not currentRequest.get().isPostRequest
                or ("bounce" in kwargs and kwargs["bounce"] == "1"
                    )  # review before adding
            ):
            return self.render.add(skel)
        if not securitykey.validate(skey, useSessionKey=True):
            raise errors.PreconditionFailed()
        skel["parententry"] = parentNodeSkel["key"]
        # parentrepo may not exist of parentNodeSkel as it may be an rootNode
        skel["parentrepo"] = parentNodeSkel[
            "parentrepo"] if "parentrepo" in parentNodeSkel else parentNodeSkel[
                "key"]
        skel.toDB()
        self.onAdded(skel)
        return self.render.addSuccess(skel)
Exemple #8
0
    def index(self, *args, **kwargs):
        """
		The first two lines of code here ensure that requesting a non-existent module or template will throw a 404
		instead of referring to index. Remove them if you wish to alter this behaviour.
		"""
        if len(args) > 1 or kwargs:
            raise errors.NotFound()

        template = self.render.getEnv().get_template("index.html")
        return template.render(start=True)
Exemple #9
0
    def getTemplateFileName(self, template, ignoreStyle=False):
        """
			Returns the filename of the template.

			This function decides in which language and which style a given template is rendered.
			The style is provided as get-parameters for special-case templates that differ from
			their usual way.

			It is advised to override this function in case that
			:func:`server.render.jinja2.default.Render.getLoaders` is redefined.

			:param template: The basename of the template to use.
			:type template: str

			:param ignoreStyle: Ignore any maybe given style hints.
			:type ignoreStyle: bool

			:returns: Filename of the template
			:rtype: str
		"""
        validChars = "abcdefghijklmnopqrstuvwxyz1234567890-"
        if "htmlpath" in dir(self):
            htmlpath = self.htmlpath
        else:
            htmlpath = "html"
        currReq = currentRequest.get()
        if not ignoreStyle \
         and "style" in currReq.kwargs \
         and all([x in validChars for x in currReq.kwargs["style"].lower()]):
            stylePostfix = "_" + currReq.kwargs["style"]
        else:
            stylePostfix = ""
        lang = currentLanguage.get()  # session.current.getLanguage()
        fnames = [template + stylePostfix + ".html", template + ".html"]
        if lang:
            fnames = [
                os.path.join(lang, template + stylePostfix + ".html"),
                template + stylePostfix + ".html",
                os.path.join(lang, template + ".html"), template + ".html"
            ]
        for fn in fnames:  # check subfolders
            prefix = template.split("_")[0]
            if os.path.isfile(
                    os.path.join(utils.projectBasePath, htmlpath, prefix, fn)):
                return ("%s/%s" % (prefix, fn))
        for fn in fnames:  # Check the templatefolder of the application
            if os.path.isfile(os.path.join(utils.projectBasePath, htmlpath,
                                           fn)):
                return fn
        for fn in fnames:  # Check the fallback
            if os.path.isfile(
                    os.path.join(utils.projectBasePath, "viur", "core",
                                 "template", fn)):
                return fn
        raise errors.NotFound("Template %s not found." % template)
Exemple #10
0
def index(*args, **kwargs):
	from viur.core.render import isAdminAvailable, isViAvailable
	if not isAdminAvailable():
		if isViAvailable():
			# The admin is not available, the Vi however is, so redirect there
			raise errors.Redirect("/vi")
		raise errors.NotFound()
	if currentRequest.get().isDevServer or currentRequest.get().isSSLConnection:
		raise errors.Redirect("/admin/s/admin.html")
	else:
		appVersion = currentRequest.get().request.host
		raise errors.Redirect("https://%s/admin/s/admin.html" % appVersion)
Exemple #11
0
    def index(self, template="index", *arg, **kwargs):
        if ".." in template or "/" in template:
            return

        try:

            template = self.render.getEnv().get_template(
                self.render.getTemplateFileName("sites/" + template))
        except:
            raise errors.NotFound()

        return template.render()
Exemple #12
0
    def edit(self, *args, **kwargs):
        """
			Modify an existing entry, and render the entry, eventually with error notes on incorrect data.
			Data is taken by any other arguments in *kwargs*.

			The entry is fetched by its entity key, which either is provided via *kwargs["key"]*,
			or as the first parameter in *args*. The function performs several access control checks
			on the requested entity before it is modified.

			.. seealso:: :func:`editSkel`, :func:`onEdit`, :func:`onEdited`, :func:`canEdit`

			:returns: The rendered, edited object of the entry, eventually with error hints.

			:raises: :exc:`viur.core.errors.NotAcceptable`, when no *key* is provided.
			:raises: :exc:`viur.core.errors.NotFound`, when no entry with the given *key* was found.
			:raises: :exc:`viur.core.errors.Unauthorized`, if the current user does not have the required permissions.
			:raises: :exc:`viur.core.errors.PreconditionFailed`, if the *skey* could not be verified.
		"""
        if "skey" in kwargs:
            skey = kwargs["skey"]
        else:
            skey = ""
        if "key" in kwargs:
            key = kwargs["key"]
        elif len(args) == 1:
            key = args[0]
        else:
            raise errors.NotAcceptable()
        skel = self.editSkel()
        if not skel.fromDB(key):
            raise errors.NotFound()
        if not self.canEdit(skel):
            raise errors.Unauthorized()
        if (len(kwargs) == 0  # no data supplied
                or skey == ""  # no security key
                or not currentRequest.get().
                isPostRequest  # failure if not using POST-method
                or not skel.fromClient(
                    kwargs)  # failure on reading into the bones
                or ("bounce" in kwargs and kwargs["bounce"] == "1"
                    )  # review before changing
            ):
            # render the skeleton in the version it could as far as it could be read.
            return self.render.edit(skel)
        if not securitykey.validate(skey, useSessionKey=True):
            raise errors.PreconditionFailed()

        self.onEdit(skel)
        skel.toDB()  # write it!
        self.onEdited(skel)

        return self.render.editSuccess(skel)
Exemple #13
0
	def edit(self, skelType, key, skey="", *args, **kwargs):
		"""
		Modify an existing entry, and render the entry, eventually with error notes on incorrect data.
		Data is taken by any other arguments in *kwargs*.

		The function performs several access control checks on the requested entity before it is added.

		.. seealso:: :func:`onItemAdded`, :func:`canEdit`

		:param skelType: Defines the type of the entry that should be modified and may either be "node" or "leaf".
		:type skelType: str
		:param key: URL-safe key of the item to be edited.
		:type key: str

		:returns: The rendered, modified object of the entry, eventually with error hints.

		:raises: :exc:`server.errors.NotAcceptable`, when no valid *skelType* was provided.
		:raises: :exc:`server.errors.NotFound`, when no valid *node* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		:raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified.
		"""
		if skelType == "node":
			skel = self.viewSkel(TreeType.Node)
		elif skelType == "leaf" and self.hasDistinctLeafs:
			skel = self.viewSkel(TreeType.Leaf)
		else:
			raise errors.NotAcceptable()

		if not skel.fromDB(key):
			raise errors.NotFound()

		if not self.canEdit(skelType, skel):
			raise errors.Unauthorized()

		if (len(kwargs) == 0  # no data supplied
				or skey == ""  # no security key
				# or not request.current.get().isPostRequest fixme: POST-method check missing?  # failure if not using POST-method
				or not skel.fromClient(kwargs)  # failure on reading into the bones
				or ("bounce" in kwargs and kwargs["bounce"] == "1")  # review before adding
		):
			return self.render.edit(skel)

		if not securitykey.validate(skey, useSessionKey=True):
			raise errors.PreconditionFailed()

		skel.toDB()
		self.onItemEdited(skel)

		return self.render.editItemSuccess(skel)
Exemple #14
0
    def download(self,
                 blobKey,
                 fileName="",
                 download="",
                 sig="",
                 *args,
                 **kwargs):
        """
		Download a file.
		:param blobKey: The unique blob key of the file.
		:type blobKey: str
		:param fileName: Optional filename to provide in the header.
		:type fileName: str
		:param download: Set header to attachment retrival, set explictly to "1" if download is wanted.
		:type download: str
		"""
        global credentials, bucket
        if not sig:
            raise errors.PreconditionFailed()
        # First, validate the signature, otherwise we don't need to proceed any further
        if not utils.hmacVerify(blobKey.encode("ASCII"), sig):
            raise errors.Forbidden()
        # Split the blobKey into the individual fields it should contain
        dlPath, validUntil = urlsafe_b64decode(blobKey).decode("UTF-8").split(
            "\0")
        if validUntil != "0" and datetime.strptime(
                validUntil, "%Y%m%d%H%M") < datetime.now():
            raise errors.Gone()
        # Create a signed url and redirect the user
        if isinstance(credentials, ServiceAccountCredentials
                      ):  # We run locally with an service-account.json
            blob = bucket.get_blob(dlPath)
            if not blob:
                raise errors.NotFound()
            signed_url = blob.generate_signed_url(datetime.now() +
                                                  timedelta(seconds=60))
        else:  # We are inside the appengine
            auth_request = requests.Request()
            signed_blob_path = bucket.blob(dlPath)
            expires_at_ms = datetime.now() + timedelta(seconds=60)
            signing_credentials = compute_engine.IDTokenCredentials(
                auth_request,
                "",
                service_account_email=credentials.service_account_email)
            signed_url = signed_blob_path.generate_signed_url(
                expires_at_ms, credentials=signing_credentials, version="v4")
        raise errors.Redirect(signed_url)
Exemple #15
0
	def delete(self, skelType, key, *args, **kwargs):
		"""
		Deletes an entry or an directory (including its contents).

		The function runs several access control checks on the data before it is deleted.

		.. seealso:: :func:`canDelete`, :func:`onItemDeleted`

		:param skelType: Defines the type of the entry that should be deleted and may either be "node" or "leaf".
		:type skelType: str
		:param key: URL-safe key of the item to be deleted.
		:type key: str

		:returns: The rendered, deleted object of the entry.

		:raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		:raises: :exc:`server.errors.PreconditionFailed`, if the *skey* could not be verified.
		"""
		if skelType == "node":
			skel = self.viewSkel(TreeType.Node)
		elif skelType == "leaf" and self.hasDistinctLeafs:
			skel = self.viewSkel(TreeType.Leaf)
		else:
			raise errors.NotAcceptable()

		if "skey" in kwargs:
			skey = kwargs["skey"]
		else:
			skey = ""

		if not skel.fromDB(key):
			raise errors.NotFound()

		if not self.canDelete(skelType, skel):
			raise errors.Unauthorized()
		if not securitykey.validate(skey, useSessionKey=True):
			raise errors.PreconditionFailed()

		if skelType == "node":
			self.deleteRecursive(key)
		skel.delete()

		self.onItemDeleted(skel)
		return self.render.deleteSuccess(skel, skelType=skelType)
Exemple #16
0
    def add(self, skelType, node, *args, **kwargs):
        ## We can't add files directly (they need to be uploaded
        # if skelType != "node":
        #	raise errors.NotAcceptable()
        if skelType == "leaf":  # We need to handle leafs separately here
            skey = kwargs.get("skey")
            targetKey = kwargs.get("key")
            #if not skey or not securitykey.validate(skey, useSessionKey=True) or not targetKey:
            #	raise errors.PreconditionFailed()

            skel = self.addLeafSkel()
            if not skel.fromDB(targetKey):
                raise errors.NotFound()
            if not skel["pending"]:
                raise errors.PreconditionFailed()
            skel["pending"] = False
            skel["parentdir"] = skel["pendingParentdir"]
            if skel["parentdir"]:
                rootNode = self.getRootNode(skel["parentdir"])
            else:
                rootNode = None
            if not self.canAdd("leaf", rootNode):
                raise errors.Forbidden()
            blobs = list(bucket.list_blobs(prefix="%s/" % targetKey))
            if len(blobs) != 1:
                logging.error("Invalid number of blobs in folder")
                logging.error(targetKey)
                raise errors.PreconditionFailed()
            blob = blobs[0]
            skel["mimetype"] = utils.escapeString(blob.content_type)
            skel["name"] = utils.escapeString(
                blob.name.replace("%s/source/" % targetKey, ""))
            skel["size"] = blob.size
            skel["rootnode"] = rootNode
            skel["weak"] = rootNode is None
            skel.toDB()
            # Add updated download-URL as the auto-generated isn't valid yet
            skel["downloadUrl"] = utils.downloadUrlFor(skel["dlkey"],
                                                       skel["name"],
                                                       derived=False)
            return self.render.addItemSuccess(skel)

        return super(File, self).add(skelType, node, *args, **kwargs)
Exemple #17
0
    def download(self,
                 blobKey,
                 fileName="",
                 download="",
                 sig="",
                 *args,
                 **kwargs):
        """
		Download a file.

		:param blobKey: The unique blob key of the file.
		:type blobKey: str

		:param fileName: Optional filename to provide in the header.
		:type fileName: str

		:param download: Set header to attachment retrival, set explictly to "1" if download is wanted.
		:type download: str
		"""
        if not sig:
            raise errors.PreconditionFailed()
        # if download == "1":
        #	fname = "".join(
        #		[c for c in fileName if c in string.ascii_lowercase + string.ascii_uppercase + string.digits + ".-_"])
        #	request.current.get().response.headers.add_header("Content-disposition",
        #													  ("attachment; filename=%s" % (fname)).encode("UTF-8"))
        # First, validate the signature, otherwise we don't need to proceed any further
        if not utils.hmacVerify(blobKey.encode("ASCII"), sig):
            raise errors.Forbidden()
        # Split the blobKey into the individual fields it should contain
        dlPath, validUntil = urlsafe_b64decode(blobKey).decode("UTF-8").split(
            "\0")
        if validUntil != "0" and datetime.strptime(
                validUntil, "%Y%m%d%H%M") < datetime.now():
            raise errors.Gone()
        # Create a signed url and redirect the user
        blob = bucket.get_blob(dlPath)
        if not blob:
            raise errors.NotFound()
        signed_url = blob.generate_signed_url(datetime.now() +
                                              timedelta(seconds=60))
        raise errors.Redirect(signed_url)
Exemple #18
0
    def view(self, *args, **kwargs):
        """
		Prepares and renders a single entry for viewing.

		The entry is fetched by its entity key, which either is provided via *kwargs["key"]*,
		or as the first parameter in *args*. The function performs several access control checks
		on the requested entity before it is rendered.

		.. seealso:: :func:`viewSkel`, :func:`canView`, :func:`onItemViewed`

		:returns: The rendered representation of the requested entity.

		:raises: :exc:`server.errors.NotAcceptable`, when no *key* is provided.
		:raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		"""
        if "key" in kwargs:
            key = kwargs["key"]
        elif len(args) >= 1:
            key = args[0]
        else:
            raise errors.NotAcceptable()
        if not len(key):
            raise errors.NotAcceptable()
        skel = self.viewSkel()
        if key == u"structure":
            # We dump just the structure of that skeleton, including it's default values
            if not self.canView(skel):
                raise errors.Unauthorized()
        else:  # We return a single entry for viewing
            # We probably have a Database or SEO-Key here
            #seoKey = "viur.viurActiveSeoKeys ="
            #skel = self.viewSkel().all().filter(seoKey, args[0]).getSkel()
            skel = self.viewSkel()
            if not skel.fromDB(key):
                raise errors.NotFound()
            if not self.canView(skel):
                raise errors.Forbidden()
            self.onItemViewed(skel)
        return self.render.view(skel)
Exemple #19
0
	def view(self, skelType, key, *args, **kwargs):
		"""
		Prepares and renders a single entry for viewing.

		The entry is fetched by its *key* and its *skelType*.
		The function performs several access control checks on the requested entity before it is rendered.

		.. seealso:: :func:`canView`, :func:`onItemViewed`

		:returns: The rendered representation of the requested entity.

		:param skelType: May either be "node" or "leaf".
		:type skelType: str
		:param node: URL-safe key of the parent.
		:type node: str

		:raises: :exc:`server.errors.NotAcceptable`, when an incorrect *skelType* is provided.
		:raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		"""
		if skelType == "node":
			skel = self.viewSkel(TreeType.Node)
		elif skelType == "leaf" and self.hasDistinctLeafs:
			skel = self.viewSkel(TreeType.Leaf)
		else:
			raise errors.NotAcceptable()
		if not key:
			raise errors.NotAcceptable()
		if key == u"structure":
			# We dump just the structure of that skeleton, including it's default values
			if not self.canView(skelType, None):
				raise errors.Unauthorized()
		else:
			# We return a single entry for viewing
			if not skel.fromDB(key):
				raise errors.NotFound()
			if not self.canView(skelType, skel):
				raise errors.Unauthorized()
			self.onItemViewed(skel)
		return self.render.view(skel)
Exemple #20
0
    def findAndCall(self, path, *args,
                    **kwargs):  # Do the actual work: process the request
        # Prevent Hash-collision attacks
        kwargs = {}
        stopCount = conf["viur.maxPostParamsCount"]
        for key, value in self.request.params.iteritems():
            if key in kwargs:
                if isinstance(kwargs[key], list):
                    kwargs[key].append(value)
                else:
                    kwargs[key] = [kwargs[key], value]
            else:
                kwargs[key] = value
            stopCount -= 1
            if not stopCount:  # We reached zero; maximum PostParamsCount exceeded
                raise errors.NotAcceptable()

        if "self" in kwargs:  # self is reserved for bound methods
            raise errors.BadRequest()
        # Parse the URL
        path = parse.urlparse(path).path
        self.pathlist = [parse.unquote(x) for x in path.strip("/").split("/")]
        caller = conf["viur.mainResolver"]
        idx = 0  # Count how may items from *args we'd have consumed (so the rest can go into *args of the called func
        for currpath in self.pathlist:
            if "canAccess" in caller and not caller["canAccess"]():
                # We have a canAccess function guarding that object,
                # and it returns False...
                raise (errors.Unauthorized())
            idx += 1
            currpath = currpath.replace("-", "_").replace(".", "_")
            if currpath in caller:
                caller = caller[currpath]
                if (("exposed" in dir(caller) and caller.exposed) or
                    ("internalExposed" in dir(caller)
                     and caller.internalExposed
                     and self.internalRequest)) and hasattr(
                         caller, '__call__'):
                    args = self.pathlist[idx:] + [
                        x for x in args
                    ]  # Prepend the rest of Path to args
                    break
            elif "index" in caller:
                caller = caller["index"]
                if (("exposed" in dir(caller) and caller.exposed) or
                    ("internalExposed" in dir(caller)
                     and caller.internalExposed
                     and self.internalRequest)) and hasattr(
                         caller, '__call__'):
                    args = self.pathlist[idx - 1:] + [x for x in args]
                    break
                else:
                    raise (errors.NotFound(
                        "The path %s could not be found" % "/".join([("".join([
                            y for y in x if y.lower() in
                            "0123456789abcdefghijklmnopqrstuvwxyz"
                        ])) for x in self.pathlist[:idx]])))
            else:
                raise (errors.NotFound(
                    "The path %s could not be found" % "/".join([("".join([
                        y for y in x
                        if y.lower() in "0123456789abcdefghijklmnopqrstuvwxyz"
                    ])) for x in self.pathlist[:idx]])))
        if (not callable(caller)
                or ((not "exposed" in dir(caller) or not caller.exposed)) and
            (not "internalExposed" in dir(caller) or not caller.internalExposed
             or not self.internalRequest)):
            if "index" in caller \
             and (callable(caller["index"]) \
               and ("exposed" in dir(caller["index"]) and caller["index"].exposed) \
               or ("internalExposed" in dir(
              caller["index"]) and caller["index"].internalExposed and self.internalRequest)):
                caller = caller["index"]
            else:
                raise (errors.MethodNotAllowed())
        # Check for forceSSL flag
        if not self.internalRequest \
         and "forceSSL" in dir(caller) \
         and caller.forceSSL \
         and not self.request.host_url.lower().startswith("https://") \
         and not self.isDevServer:
            raise (errors.PreconditionFailed(
                "You must use SSL to access this ressource!"))
        # Check for forcePost flag
        if "forcePost" in dir(
                caller) and caller.forcePost and not self.isPostRequest:
            raise (errors.MethodNotAllowed(
                "You must use POST to access this ressource!"))
        self.args = []
        for arg in args:
            if isinstance(arg, str):
                self.args.append(arg)
            else:
                try:
                    self.args.append(arg.decode("UTF-8"))
                except:
                    pass
        self.kwargs = kwargs
        # Check if this request should bypass the caches
        if self.request.headers.get("X-Viur-Disable-Cache"):
            from viur.core import utils
            # No cache requested, check if the current user is allowed to do so
            user = utils.getCurrentUser()
            if user and "root" in user["access"]:
                logging.debug(
                    "Caching disabled by X-Viur-Disable-Cache header")
                self.disableCache = True
        try:
            if (conf["viur.debug.traceExternalCallRouting"]
                    and not self.internalRequest
                ) or conf["viur.debug.traceInternalCallRouting"]:
                logging.debug("Calling %s with args=%s and kwargs=%s" %
                              (str(caller), str(args), str(kwargs)))
            res = caller(*self.args, **self.kwargs)
            res = str(res).encode("UTF-8") if not isinstance(res,
                                                             bytes) else res
            self.response.write(res)
        except TypeError as e:
            if self.internalRequest:  # We provide that "service" only for requests originating from outside
                raise
            # Check if the function got too few arguments and raise a NotAcceptable error
            tmpRes = {}
            argsOrder = list(
                caller.__code__.co_varnames)[1:caller.__code__.co_argcount]
            # Map default values in
            reversedArgsOrder = argsOrder[::-1]
            for defaultValue in list(caller.__defaults__ or [])[::-1]:
                tmpRes[reversedArgsOrder.pop(0)] = defaultValue
            del reversedArgsOrder
            # Map args in
            setArgs = []  # Store a list of args already set by *args
            for idx in range(0, min(len(args), len(argsOrder))):
                setArgs.append(argsOrder[idx])
                tmpRes[argsOrder[idx]] = args[idx]
            # Last, we map the kwargs in
            for k, v in kwargs.items():
                if k in setArgs:  # This key has already been set by *args
                    raise (
                        errors.NotAcceptable()
                    )  # We reraise that exception as we got duplicate arguments
                tmpRes[k] = v
            # Last check, that every parameter is satisfied:
            if not all([x in tmpRes.keys() for x in argsOrder]):
                raise (errors.NotAcceptable())
            raise
Exemple #21
0
    def upload(self, node=None, *args, **kwargs):
        try:
            canAdd = self.canAdd("leaf", node)
        except:
            canAdd = False
        if not canAdd:
            for upload in self.getUploads():
                upload.delete()
            raise errors.Forbidden()

        try:
            res = []
            if node:
                # The file is uploaded into a rootNode
                nodeSkel = self.editNodeSkel()
                if not nodeSkel.fromDB(node):
                    for upload in self.getUploads():
                        upload.delete()
                    raise errors.NotFound()
                else:
                    weak = False
                    parentDir = str(node)
                    parentRepo = nodeSkel["parentrepo"]
            else:
                weak = True
                parentDir = None
                parentRepo = None

            # Handle the actual uploads
            for upload in self.getUploads():
                fileName = decodeFileName(upload.filename)
                height = width = 0

                if str(upload.content_type).startswith("image/"):
                    try:
                        servingURL = images.get_serving_url(upload.key())
                        if request.current.get().isDevServer:
                            # NOTE: changed for Ticket ADMIN-37
                            servingURL = urlparse(servingURL).path
                        elif servingURL.startswith("http://"):
                            # Rewrite Serving-URLs to https if we are live
                            servingURL = servingURL.replace(
                                "http://", "https://")
                    except:
                        servingURL = ""

                    try:
                        # only fetching the file header or all if the file is smaller than 1M
                        data = blobstore.fetch_data(upload.key(), 0,
                                                    min(upload.size, 1000000))
                        image = images.Image(image_data=data)
                        height = image.height
                        width = image.width
                    except Exception as err:
                        logging.error(
                            "some error occurred while trying to fetch the image header with dimensions"
                        )
                        logging.exception(err)

                else:
                    servingURL = ""

                fileSkel = self.addLeafSkel()

                fileSkel.setValues({
                    "name":
                    utils.escapeString(fileName),
                    "size":
                    upload.size,
                    "mimetype":
                    utils.escapeString(upload.content_type),
                    "dlkey":
                    str(upload.key()),
                    "servingurl":
                    servingURL,
                    "parentdir":
                    parentDir,
                    "parentrepo":
                    parentRepo,
                    "weak":
                    weak,
                    "width":
                    width,
                    "height":
                    height
                })
                fileSkel.toDB()
                res.append(fileSkel)
                self.onItemUploaded(fileSkel)

            # Uploads stored successfully, generate response to the client
            for r in res:
                logging.info("Upload successful: %s (%s)" %
                             (r["name"], r["dlkey"]))
            user = utils.getCurrentUser()

            if user:
                logging.info("User: %s (%s)" % (user["name"], user["key"]))

            return self.render.addItemSuccess(res)

        except Exception as err:
            logging.exception(err)

            for upload in self.getUploads():
                upload.delete()
                utils.markFileForDeletion(str(upload.key()))

            raise errors.InternalServerError()
Exemple #22
0
    def index(self, *args, **kwargs):
        if len(args) > 1 or kwargs:
            raise errors.NotFound()

        template = self.render.getEnv().get_template("index.html")
        return template.render(start=True)
Exemple #23
0
    def findAndCall(self, path: str, *args, **kwargs):
        """
			Does the actual work of sanitizing the parameter, determine which @exposed (or @internalExposed) function
			to call (and with witch parameters)
		"""
        # Prevent Hash-collision attacks
        kwargs = {}
        stopCount = conf["viur.maxPostParamsCount"]
        try:
            for key, value in self.request.params.iteritems():
                key = unicodedata.normalize("NFC", key)
                value = unicodedata.normalize("NFC", value)
                if key.startswith(
                        "_"
                ):  # Ignore keys starting with _ (like VI's _unused_time_stamp)
                    continue
                if key in kwargs:
                    if isinstance(kwargs[key], list):
                        kwargs[key].append(value)
                    else:  # Convert that key to a list
                        kwargs[key] = [kwargs[key], value]
                else:
                    kwargs[key] = value
                stopCount -= 1
                if not stopCount:  # We reached zero; maximum PostParamsCount exceeded
                    raise errors.NotAcceptable()
        except UnicodeError:
            # We received invalid unicode data (usually happens when someone tries to exploit unicode normalisation bugs)
            raise errors.BadRequest()
        if "self" in kwargs or "return" in kwargs:  # self or return is reserved for bound methods
            raise errors.BadRequest()
        # Parse the URL
        path = parse.urlparse(path).path
        self.pathlist = [
            unicodedata.normalize("NFC", parse.unquote(x))
            for x in path.strip("/").split("/")
        ]
        caller = conf["viur.mainResolver"]
        idx = 0  # Count how may items from *args we'd have consumed (so the rest can go into *args of the called func
        for currpath in self.pathlist:
            if "canAccess" in caller and not caller["canAccess"]():
                # We have a canAccess function guarding that object,
                # and it returns False...
                raise (errors.Unauthorized())
            idx += 1
            currpath = currpath.replace("-", "_").replace(".", "_")
            if currpath in caller:
                caller = caller[currpath]
                if (("exposed" in dir(caller) and caller.exposed) or
                    ("internalExposed" in dir(caller)
                     and caller.internalExposed
                     and self.internalRequest)) and hasattr(
                         caller, '__call__'):
                    args = self.pathlist[idx:] + [
                        x for x in args
                    ]  # Prepend the rest of Path to args
                    break
            elif "index" in caller:
                caller = caller["index"]
                if (("exposed" in dir(caller) and caller.exposed) or
                    ("internalExposed" in dir(caller)
                     and caller.internalExposed
                     and self.internalRequest)) and hasattr(
                         caller, '__call__'):
                    args = self.pathlist[idx - 1:] + [x for x in args]
                    break
                else:
                    raise (errors.NotFound(
                        "The path %s could not be found" % "/".join([("".join([
                            y for y in x if y.lower() in
                            "0123456789abcdefghijklmnopqrstuvwxyz"
                        ])) for x in self.pathlist[:idx]])))
            else:
                raise (errors.NotFound(
                    "The path %s could not be found" % "/".join([("".join([
                        y for y in x
                        if y.lower() in "0123456789abcdefghijklmnopqrstuvwxyz"
                    ])) for x in self.pathlist[:idx]])))
        if (not callable(caller)
                or ((not "exposed" in dir(caller) or not caller.exposed)) and
            (not "internalExposed" in dir(caller) or not caller.internalExposed
             or not self.internalRequest)):
            if "index" in caller \
             and (callable(caller["index"]) \
               and ("exposed" in dir(caller["index"]) and caller["index"].exposed) \
               or ("internalExposed" in dir(
              caller["index"]) and caller["index"].internalExposed and self.internalRequest)):
                caller = caller["index"]
            else:
                raise (errors.MethodNotAllowed())
        # Check for forceSSL flag
        if not self.internalRequest \
         and "forceSSL" in dir(caller) \
         and caller.forceSSL \
         and not self.request.host_url.lower().startswith("https://") \
         and not self.isDevServer:
            raise (errors.PreconditionFailed(
                "You must use SSL to access this ressource!"))
        # Check for forcePost flag
        if "forcePost" in dir(
                caller) and caller.forcePost and not self.isPostRequest:
            raise (errors.MethodNotAllowed(
                "You must use POST to access this ressource!"))
        self.args = args
        self.kwargs = kwargs
        # Check if this request should bypass the caches
        if self.request.headers.get("X-Viur-Disable-Cache"):
            from viur.core import utils
            # No cache requested, check if the current user is allowed to do so
            user = utils.getCurrentUser()
            if user and "root" in user["access"]:
                logging.debug(
                    "Caching disabled by X-Viur-Disable-Cache header")
                self.disableCache = True
        try:
            annotations = typing.get_type_hints(caller)
            if annotations and not self.internalRequest:
                newKwargs = {
                }  # The dict of new **kwargs we'll pass to the caller
                newArgs = []  # List of new *args we'll pass to the caller
                argsOrder = list(
                    caller.__code__.co_varnames)[1:caller.__code__.co_argcount]
                # Map args in
                for idx in range(0, min(len(self.args), len(argsOrder))):
                    paramKey = argsOrder[idx]
                    if paramKey in annotations:  # We have to enforce a type-annotation for this *args parameter
                        _, newTypeValue = self.processTypeHint(
                            annotations[paramKey], self.args[idx], True)
                        newArgs.append(newTypeValue)
                    else:
                        newArgs.append(self.args[idx])
                newArgs.extend(self.args[min(len(self.args), len(argsOrder)):])
                # Last, we map the kwargs in
                for k, v in kwargs.items():
                    if k in annotations:
                        newStrValue, newTypeValue = self.processTypeHint(
                            annotations[k], v, False)
                        self.kwargs[k] = newStrValue
                        newKwargs[k] = newTypeValue
                    else:
                        newKwargs[k] = v
            else:
                newArgs = self.args
                newKwargs = self.kwargs
            if (conf["viur.debug.traceExternalCallRouting"]
                    and not self.internalRequest
                ) or conf["viur.debug.traceInternalCallRouting"]:
                logging.debug("Calling %s with args=%s and kwargs=%s" %
                              (str(caller), str(newArgs), str(newKwargs)))
            res = caller(*newArgs, **newKwargs)
            res = str(res).encode("UTF-8") if not isinstance(res,
                                                             bytes) else res
            self.response.write(res)
        except TypeError as e:
            if self.internalRequest:  # We provide that "service" only for requests originating from outside
                raise
            if "viur/core/request.py\", line 5" in traceback.format_exc(
            ).splitlines()[-3]:
                # Don't raise NotAcceptable for type-errors raised deep somewhere inside caller.
                # We check if the last line in traceback originates from viur/core/request.py and a line starting with
                # 5 and only raise NotAcceptable then. Otherwise a "normal" 500 Server error will be raised.
                # This is kinda hackish, however this is much faster than reevaluating the args and kwargs passed
                # to caller as we did in ViUR2.
                raise errors.NotAcceptable()
            raise
Exemple #24
0
    def move(self, skelType: str, key: str, parentNode: str, *args,
             **kwargs) -> str:
        """
		Move a node (including its contents) or a leaf to another node.

		.. seealso:: :func:`canMove`

		:param skelType: Defines the type of the entry that should be moved and may either be "node" or "leaf".
		:param key: URL-safe key of the item to be moved.
		:param parentNode: URL-safe key of the destination node, which must be a node.

		:returns: The rendered, edited object of the entry.

		:raises: :exc:`viur.core.errors.NotFound`, when no entry with the given *key* was found.
		:raises: :exc:`viur.core.errors.Unauthorized`, if the current user does not have the required permissions.
		:raises: :exc:`viur.core.errors.PreconditionFailed`, if the *skey* could not be verified.
		"""
        if not self._checkSkelType(skelType):
            raise errors.NotAcceptable()

        skel = self.addSkel(skelType)  # srcSkel - the skeleton to be moved
        parentNodeSkel = self.editSkel(
            "node")  # destSkel - the node it should be moved into

        if not skel.fromDB(key) or not parentNodeSkel.fromDB(parentNode):
            # Could not find one of the entities
            raise errors.NotFound()

        if not self.canMove(skelType, skel, parentNodeSkel):
            raise errors.Unauthorized()

        if skel["key"] == parentNodeSkel["key"]:
            # Cannot move a node into itself
            raise errors.NotAcceptable()

        ## Test for recursion
        currLevel = db.Get(parentNodeSkel["key"])
        for x in range(0, 99):
            if currLevel.key == skel["key"]:
                break
            if "rootNode" in currLevel and currLevel["rootNode"] == 1:
                # We reached a rootNode, so this is okay
                break
            currLevel = db.Get(currLevel["parententry"])
        else:  # We did not "break" - recursion-level exceeded or loop detected
            raise errors.NotAcceptable()

        # Test if we try to move a rootNode
        tmp = skel.dbEntity
        if "rootNode" in tmp and tmp["rootNode"] == 1:
            # Cant move a rootNode away..
            raise errors.NotAcceptable()

        if not securitykey.validate(kwargs.get("skey", ""),
                                    useSessionKey=True):
            raise errors.PreconditionFailed()

        currentParentRepo = skel["parentrepo"]
        skel["parententry"] = parentNodeSkel["key"]
        skel["parentrepo"] = parentNodeSkel[
            "parentrepo"]  # Fixme: Need to recursive fixing to parentrepo?
        if "sortindex" in kwargs:
            try:
                skel["sortindex"] = float(kwargs["sortindex"])
            except:
                raise errors.PreconditionFailed()
        skel.toDB()

        # Ensure a changed parentRepo get's proagated
        if currentParentRepo != parentNodeSkel["parentrepo"]:
            self.updateParentRepo(key, parentNodeSkel["parentrepo"])
        return self.render.editSuccess(
            skel
        )  # new Sig, has no args and kwargs , skelType = skelType, action = "move", destNode = parentNodeSkel )
Exemple #25
0
		:type skelType: str
		:param node: URL-safe key of the parent.
		:type node: str

		:raises: :exc:`server.errors.NotAcceptable`, when an incorrect *skelType* is provided.
		:raises: :exc:`server.errors.NotFound`, when no entry with the given *key* was found.
		:raises: :exc:`server.errors.Unauthorized`, if the current user does not have the required permissions.
		"""
        if not (skelType := self._checkSkelType(skelType)):
            raise errors.NotAcceptable(f"Invalid skelType provided.")
        skel = self.viewSkel(skelType)
        if not key:
            raise errors.NotAcceptable()
        # We return a single entry for viewing
        if not skel.fromDB(key):
            raise errors.NotFound()
        if not self.canView(skelType, skel):
            raise errors.Unauthorized()
        self.onView(skelType, skel)
        return self.render.view(skel)

    @exposed
    @forceSSL
    def add(self, skelType, node, *args, **kwargs):
        """
		Add a new entry with the given parent *node*, and render the entry, eventually with error notes
		on incorrect data. Data is taken by any other arguments in *kwargs*.

		The function performs several access control checks on the requested entity before it is added.

		.. seealso:: :func:`canAdd`, :func:`onAdd`, , :func:`onAdded`
Exemple #26
0
    def pathToKey(self, key=None):
        """
		Returns the recursively expanded path through the Hierarchy from the root-node to a
		requested node.

		:param key: URL-safe key of the destination entity.
		:type key: str

		:returns: An nested dictionary with information about all nodes in the path from root \
		to the requested node.
		:rtype: dict
		"""
        def getName(obj):
            """
				Tries to return a suitable name for the given object.
			"""
            if "name" in obj:
                return obj["name"]

            skel = self.viewSkel()
            if "name" in skel:
                nameBone = getattr(skel, "name")

                if (isinstance(nameBone, baseBone)
                        and "languages" in dir(nameBone)
                        and nameBone.languages):
                    skel.setValues(obj)
                    return str(skel["name"])

            return None

        availableRepos = self.getAvailableRootNodes()
        if not key:
            try:
                key = availableRepos[0]["key"]
            except:
                raise errors.NotFound()

            keylist = []
        else:
            if str(key).isdigit():
                key = str(db.Key.from_path(self.viewSkel().kindName,
                                           long(key)))
            keylist = [key]

        if not self.canList(key):
            raise errors.Unauthorized()

        res = []

        lastChildren = []

        for x in range(0, 99):
            q = db.Query(self.viewSkel().kindName)
            q.filter("parententry =", str(key))
            q.order("sortindex")
            entryObjs = q.run(100)
            lastChildren = res[:]
            res = []

            for obj in entryObjs:
                if "parententry" in obj:
                    parent = str(obj["parententry"])
                else:
                    parent = None

                r = {
                    "name": getName(obj),
                    "key": str(obj.key()),
                    "parent": parent,
                    "hrk": obj["hrk"] if "hrk" in obj else None,
                    "active": (str(obj.key()) in keylist)
                }

                if r["active"]:
                    r["children"] = lastChildren

                res.append(r)

            if key in [x["key"] for x in availableRepos]:
                break
            else:
                item = db.Get(str(key))

                if item and "parententry" in item:
                    keylist.append(key)
                    key = item["parententry"]

                else:
                    break

        return res