Ejemplo n.º 1
0
def downloadUrlFor(render: 'viur.core.render.html.default.Render', fileObj: dict,
				   expires: Union[None, int] = conf["viur.downloadUrlFor.expiration"],
				   derived: Optional[str] = None, downloadFileName: Optional[str] = None) -> Optional[str]:
	"""
		Constructs a signed download-url for the given file-bone. Mostly a wrapper around
		:meth:`viur.core.utils.downloadUrlFor`.

		:param fileObj: The file-bone (eg. skel["file"])
		:param expires: None if the file is supposed to be public (which causes it to be cached on the google ede
			caches), otherwise it's lifetime in seconds
		:param derived: Optional the filename of a derived file, otherwise the the download-link will point to the
			originally uploaded file.
		:return: THe signed download-url relative to the current domain (eg /download/...)
	"""
	if expires is unsetMarker:
		raise ValueError("expires must be explicitly set")
	if "dlkey" not in fileObj and "dest" in fileObj:
		fileObj = fileObj["dest"]
	if expires:
		expires = timedelta(minutes=expires)
	if not isinstance(fileObj, (SkeletonInstance, dict)) or "dlkey" not in fileObj or "name" not in fileObj:
		return None
	if derived and ("derived" not in fileObj or not isinstance(fileObj["derived"], dict)):
		return None
	if derived:
		return utils.downloadUrlFor(folder=fileObj["dlkey"], fileName=derived, derived=True, expires=expires, downloadFileName=downloadFileName)
	else:
		return utils.downloadUrlFor(folder=fileObj["dlkey"], fileName=fileObj["name"], derived=False, expires=expires, downloadFileName=downloadFileName)
Ejemplo n.º 2
0
def downloadUrlFor(render, fileObj, derived=None, expires=timedelta(hours=1)):
	if not isinstance(fileObj, (SkeletonInstance, dict)) or "dlkey" not in fileObj or "name" not in fileObj:
		return None
	if derived and ("derived" not in fileObj or not isinstance(fileObj["derived"], dict)):
		return None
	if derived:
		return utils.downloadUrlFor(folder=fileObj["dlkey"], fileName=derived, derived=True, expires=expires)
	else:
		return utils.downloadUrlFor(folder=fileObj["dlkey"], fileName=fileObj["name"], derived=False, expires=expires)
Ejemplo n.º 3
0
 def unserialize(self, skel, name):
     if "dlkey" in skel.dbEntity and "name" in skel.dbEntity:
         skel.accessedValues[name] = utils.downloadUrlFor(skel["dlkey"],
                                                          skel["name"],
                                                          derived=False)
         return True
     return False
Ejemplo n.º 4
0
def srcSetFor(render, fileObj, expires=timedelta(hours=1)):
	if not isinstance(fileObj, (SkeletonInstance, dict)) or not "dlkey" in fileObj or "derived" not in fileObj:
		return None
	if not isinstance(fileObj["derived"], dict):
		return ""
	resList = []
	for fileName, deriviation in fileObj["derived"].items():
		params = deriviation["params"]
		if params.get("group") == "srcset":
			resList.append("%s %sw" % (utils.downloadUrlFor(fileObj["dlkey"], fileName, True, expires), params["width"]))
	return ", ".join(resList)
Ejemplo n.º 5
0
def importBlobFromViur2(dlKey, fileName):
    if not conf.get("viur.viur2import.blobsource"):
        return False
    existingImport = db.Get(db.Key("viur-viur2-blobimport", dlKey))
    if existingImport:
        if existingImport["success"]:
            return existingImport["dlurl"]
        return False
    if conf["viur.viur2import.blobsource"]["infoURL"]:
        try:
            importDataReq = urlopen(
                conf["viur.viur2import.blobsource"]["infoURL"] + dlKey)
        except:
            marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
            marker["success"] = False
            marker["error"] = "Failed URL-FETCH 1"
            db.Put(marker)
            return False
        if importDataReq.status != 200:
            marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
            marker["success"] = False
            marker["error"] = "Failed URL-FETCH 2"
            db.Put(marker)
            return False
        importData = json.loads(importDataReq.read())
        oldBlobName = conf["viur.viur2import.blobsource"][
            "gsdir"] + "/" + importData["key"]
        srcBlob = storage.Blob(
            bucket=bucket,
            name=conf["viur.viur2import.blobsource"]["gsdir"] + "/" +
            importData["key"])
    else:
        oldBlobName = conf["viur.viur2import.blobsource"]["gsdir"] + "/" + dlKey
        srcBlob = storage.Blob(
            bucket=bucket,
            name=conf["viur.viur2import.blobsource"]["gsdir"] + "/" + dlKey)
    if not srcBlob.exists():
        marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
        marker["success"] = False
        marker["error"] = "Local SRC-Blob missing"
        marker["oldBlobName"] = oldBlobName
        db.Put(marker)
        return False
    bucket.rename_blob(srcBlob, "%s/source/%s" % (dlKey, fileName))
    marker = db.Entity(db.Key("viur-viur2-blobimport", dlKey))
    marker["success"] = True
    marker["old_src_key"] = dlKey
    marker["old_src_name"] = fileName
    marker["dlurl"] = utils.downloadUrlFor(dlKey, fileName, False, None)
    db.Put(marker)
    return marker["dlurl"]
Ejemplo n.º 6
0
def srcSetFor(render: 'viur.core.render.html.default.Render', fileObj: dict, expires: Optional[int],
			  width: Optional[int] = None, height: Optional[int] = None) -> str:
	"""
		Generates a string suitable for use as the srcset tag in html. This functionality provides the browser
		with a list of images in different sizes and allows it to choose the smallest file that will fill it's viewport
		without upscaling.
		:param render: The render instance that's calling this function
		:param fileObj: The file-bone (or if multiple=True a single value from it) to generate the srcset for
		:param expires: None if the file is supposed to be public (which causes it to be cached on the google ede
			caches), otherwise it's lifetime in seconds
		:param width: A list of widths that should be included in the srcset. If a given width is not available, it will
			be skipped.
		:param height: A list of heights that should be included in the srcset. If a given height is not available,
			it will	be skipped.
		:return: The srctag generated or an empty string if a invalid file object was supplied
	"""
	if not width and not height:
		logging.error("Neither width or height supplied to srcSetFor")
		return ""
	if "dlkey" not in fileObj and "dest" in fileObj:
		fileObj = fileObj["dest"]
	if expires:
		expires = timedelta(minutes=expires)
	if not isinstance(fileObj, (SkeletonInstance, dict)) or not "dlkey" in fileObj or "derived" not in fileObj:
		logging.error("Invalid fileObj supplied to srcSetFor")
		return ""
	if not isinstance(fileObj["derived"], dict):
		return ""
	resList = []
	for fileName, derivate in fileObj["derived"]["files"].items():
		customData = derivate.get("customData", {})
		if width and customData.get("width") in width:
			resList.append("%s %sw" % (utils.downloadUrlFor(fileObj["dlkey"], fileName, True, expires), customData["width"]))
		if height and customData.get("height") in height:
			resList.append("%s %sh" % (utils.downloadUrlFor(fileObj["dlkey"], fileName, True, expires), customData["height"]))
	return ", ".join(resList)
Ejemplo n.º 7
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)
Ejemplo n.º 8
0
	def renderSkelValues(self, skel, injectDownloadURL=False):
		"""
		Prepares values of one :class:`server.db.skeleton.Skeleton` or a list of skeletons for output.

		:param skel: Skeleton which contents will be processed.
		:type skel: server.db.skeleton.Skeleton

		:returns: A dictionary or list of dictionaries.
		:rtype: dict
		"""
		if skel is None:
			return None
		elif isinstance(skel, dict):
			return skel
		res = {}
		for key, bone in skel.items():
			res[key] = self.renderBoneValue(bone, skel, key)
		if injectDownloadURL and "dlkey" in skel and "name" in skel:
			res["downloadUrl"] = utils.downloadUrlFor(skel["dlkey"], skel["name"], derived=False,
													  expires=config.conf["viur.render.json.downloadUrlExpiration"])
		return res
Ejemplo n.º 9
0
	def handle_starttag(self, tag, attrs):
		""" Delete all tags except for legal ones """
		filterChars = "\"'\\\0\r\n@()"
		if self.validHtml and tag in self.validHtml["validTags"]:
			cacheTagStart = '<' + tag
			isBlankTarget = False
			styles = None
			classes = None
			for k, v in attrs:
				k = k.strip()
				v = v.strip()
				if any([c in k for c in filterChars]) or any([c in v for c in filterChars]):
					if k in {"title", "href", "alt"} and not any([c in v for c in "\"'\\\0\r\n"]):
						# If we have a title or href attribute, ignore @ and ()
						pass
					else:
						# Either the key or the value contains a character that's not supposed to be there
						continue
				elif k == "class":
					# Classes are handled below
					classes = v.split(" ")
					continue
				elif k == "style":
					# Styles are handled below
					styles = v.split(";")
					continue
				elif k == "src":
					# We ensure that any src tag starts with an actual url
					checker = v.lower()
					if not (checker.startswith("http://") or checker.startswith("https://") or checker.startswith("/")):
						continue
					blobKey, derived, fileName = parseDownloadUrl(v)
					if blobKey:
						v = utils.downloadUrlFor(blobKey, fileName, derived, expires=None)
						if self.srcSet:
							# Build the src set with files already available. If a derived file is not yet build,
							# getReferencedBlobs will catch it, build it, and we're going to be re-called afterwards.
							fileObj = db.Query("file").filter("dlkey =", blobKey)\
								.order(("creationdate", db.SortOrder.Ascending)).getEntry()
							srcSet = utils.srcSetFor(fileObj, None, self.srcSet.get("width"), self.srcSet.get("height"))
							cacheTagStart += ' srcSet="%s"' % srcSet
				if not tag in self.validHtml["validAttrs"].keys() or not k in self.validHtml["validAttrs"][tag]:
					# That attribute is not valid on this tag
					continue
				if k.lower()[0:2] != 'on' and v.lower()[0:10] != 'javascript':
					cacheTagStart += ' %s="%s"' % (k, v)
				if tag == "a" and k == "target" and v.lower() == "_blank":
					isBlankTarget = True
			if styles:
				syleRes = {}
				for s in styles:
					style = s[: s.find(":")].strip()
					value = s[s.find(":") + 1:].strip()
					if any([c in style for c in filterChars]) or any(
						[c in value for c in filterChars]):
						# Either the key or the value contains a character that's not supposed to be there
						continue
					if value.lower().startswith("expression") or value.lower().startswith("import"):
						# IE evaluates JS inside styles if the keyword expression is present
						continue
					if style in self.validHtml["validStyles"] and not any(
						[(x in value) for x in ["\"", ":", ";"]]):
						syleRes[style] = value
				if len(syleRes.keys()):
					cacheTagStart += " style=\"%s\"" % "; ".join(
						[("%s: %s" % (k, v)) for (k, v) in syleRes.items()])
			if classes:
				validClasses = []
				for currentClass in classes:
					validClassChars = string.ascii_lowercase + string.ascii_uppercase + string.digits + "-"
					if not all([x in validClassChars for x in currentClass]):
						# The class contains invalid characters
						continue
					isOkay = False
					for validClass in self.validHtml["validClasses"]:
						# Check if the classname matches or is white-listed by a prefix
						if validClass == currentClass:
							isOkay = True
							break
						if validClass.endswith("*"):
							validClass = validClass[:-1]
							if currentClass.startswith(validClass):
								isOkay = True
								break
					if isOkay:
						validClasses.append(currentClass)
				if validClasses:
					cacheTagStart += " class=\"%s\"" % " ".join(validClasses)
			if isBlankTarget:
				# Add rel tag to prevent the browser to pass window.opener around
				cacheTagStart += " rel=\"noopener noreferrer\""
			if tag in self.validHtml["singleTags"]:
				# Single-Tags do have a visual representation; ensure it makes it into the result
				self.flushCache()
				self.result += cacheTagStart + '>'  # dont need slash in void elements in html5
			else:
				# We opened a 'normal' tag; push it on the cache so it can be discarded later if
				# we detect it has no content
				cacheTagStart += '>'
				self.tagCache.append((cacheTagStart, tag))
		else:
			self.result += " "