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)
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)
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)
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)