Esempio n. 1
0
		def untrustedCursorHelper(cursor):
			splits = str(cursor).split("_")
			if len(splits) != 3:
				raise InvalidCursorError("Invalid cursor format")
			res = "%s_%s" % (splits[0], splits[1])
			if not utils.hmacVerify(res, splits[2]):
				raise InvalidCursorError("Cursor signature invalid")
			return res
Esempio n. 2
0
	def getUploadURL(self, fileName, mimeType, size=None, skey=None, *args, **kwargs):
		node = kwargs.get("node")
		authData = kwargs.get("authData")
		authSig = kwargs.get("authSig")
		# Validate the the contentType from the client seems legit
		mimeType = mimeType.lower()
		assert len(mimeType.split("/")) == 2, "Invalid Mime-Type"
		assert all([x in string.ascii_letters + string.digits + "/-.+" for x in mimeType]), "Invalid Mime-Type"
		if authData and authSig:
			# First, validate the signature, otherwise we don't need to proceed any further
			if not utils.hmacVerify(authData.encode("ASCII"), authSig):
				raise errors.Forbidden()
			authData = json.loads(base64.b64decode(authData.encode("ASCII")).decode("UTF-8"))
			if datetime.strptime(authData["validUntil"], "%Y%m%d%H%M") < datetime.now():
				raise errors.Gone()
			if authData["validMimeTypes"]:
				for validMimeType in authData["validMimeTypes"]:
					if validMimeType == mimeType or (
						validMimeType.endswith("*") and mimeType.startswith(validMimeType[:-1])):
						break
				else:
					raise errors.NotAcceptable()
			node = authData["node"]
			maxSize = authData["maxSize"]
		else:
			if node:
				rootNode = self.getRootNode(node)
				if not self.canAdd("leaf", rootNode):
					raise errors.Forbidden()
			else:
				if not self.canAdd("leaf", None):
					raise errors.Forbidden()
			maxSize = None  # The user has some file/add permissions, don't restrict fileSize
		if maxSize:
			try:
				size = int(size)
				assert size <= maxSize
			except:  # We have a size-limit set - but no size supplied
				raise errors.PreconditionFailed()
		else:
			size = None

		if not securitykey.validate(skey, useSessionKey=True):
			raise errors.PreconditionFailed()
		targetKey, uploadUrl = self.initializeUpload(fileName, mimeType.lower(), node, size)
		resDict = {
			"uploadUrl": uploadUrl,
			"uploadKey": targetKey,
		}
		return self.render.view(resDict)
Esempio n. 3
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)
Esempio n. 4
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)
Esempio n. 5
0
def parseDownloadUrl(urlStr: str) -> Tuple[Optional[str], Optional[bool], Optional[str]]:
	"""
		Parses a file download-url (/file/download/xxxx?sig=yyyy) into it's components
		blobKey, derived (yes/no) and filename. Will return None for each component if the url
		could not be parsed.
	"""
	if not urlStr.startswith("/file/download/"):
		return None, None, None
	dataStr, sig = urlStr[15:].split("?")  # Strip /file/download/ and split on ?
	sig = sig[4:]  # Strip sig=
	if not utils.hmacVerify(dataStr.encode("ASCII"), sig):
		# Invalid signature, bail out
		return None, None, None
	# Split the blobKey into the individual fields it should contain
	try:
		dlPath, validUntil, _ = urlsafe_b64decode(dataStr).decode("UTF-8").split("\0")
	except:  # It's the old format, without an downloadFileName
		dlPath, validUntil = urlsafe_b64decode(dataStr).decode("UTF-8").split("\0")
	if validUntil != "0" and datetime.strptime(validUntil, "%Y%m%d%H%M") < datetime.now():
		# Signature expired, bail out
		return None, None, None
	blobkey, derived, fileName = dlPath.split("/")
	derived = derived != "source"
	return blobkey, derived, fileName
Esempio n. 6
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:
            # Check if the current user has the right to download *any* blob present in this application.
            # blobKey is then the path inside cloudstore - not a base64 encoded tuple
            usr = utils.getCurrentUser()
            if not usr:
                raise errors.Unauthorized()
            if "root" not in usr["access"] and "file-view" not in usr["access"]:
                raise errors.Forbidden()
            validUntil = "-1"  # Prevent this from being cached down below
            blob = bucket.get_blob(blobKey)
        else:
            # We got an request including a signature (probably a guest or a user without file-view access)
            # 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()
            blob = bucket.get_blob(dlPath)
        if not blob:
            raise errors.Gone()
        if download:
            fileName = sanitizeFileName(blob.name.split("/")[-1])
            contentDisposition = "attachment; filename=%s" % fileName
        else:
            contentDisposition = None
        if isinstance(credentials, ServiceAccountCredentials
                      ):  # We run locally with an service-account.json
            expiresAt = datetime.now() + timedelta(seconds=60)
            signedUrl = blob.generate_signed_url(
                expiresAt,
                response_disposition=contentDisposition,
                version="v4")
            raise errors.Redirect(signedUrl)
        elif utils.isLocalDevelopmentServer:  # No Service-Account to sign with - Serve everything directly
            response = utils.currentRequest.get().response
            response.headers["Content-Type"] = blob.content_type
            if contentDisposition:
                response.headers["Content-Disposition"] = contentDisposition
            return blob.download_as_bytes()
        else:  # We are inside the appengine
            if validUntil == "0":  # Its an indefinitely valid URL
                if blob.size < 5 * 1024 * 1024:  # Less than 5 MB - Serve directly and push it into the ede caches
                    response = utils.currentRequest.get().response
                    response.headers["Content-Type"] = blob.content_type
                    response.headers[
                        "Cache-Control"] = "public, max-age=604800"  # 7 Days
                    if contentDisposition:
                        response.headers[
                            "Content-Disposition"] = contentDisposition
                    return blob.download_as_bytes()
            # Default fallback - create a signed URL and redirect
            authRequest = requests.Request()
            expiresAt = datetime.now() + timedelta(seconds=60)
            signing_credentials = compute_engine.IDTokenCredentials(
                authRequest, "")
            signedUrl = blob.generate_signed_url(
                expiresAt,
                credentials=signing_credentials,
                response_disposition=contentDisposition,
                version="v4")
            raise errors.Redirect(signedUrl)