##############################################################################1#2# CoCalc: Collaborative Calculation in the Cloud3#4# Copyright (C) 2016, Sagemath Inc.5#6# This program is free software: you can redistribute it and/or modify7# it under the terms of the GNU General Public License as published by8# the Free Software Foundation, either version 3 of the License, or9# (at your option) any later version.10#11# This program is distributed in the hope that it will be useful,12# but WITHOUT ANY WARRANTY; without even the implied warranty of13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14# GNU General Public License for more details.15#16# You should have received a copy of the GNU General Public License17# along with this program. If not, see <http://www.gnu.org/licenses/>.18#19###############################################################################2021###22Blobs23###2425winston = require('winston')2627misc_node = require('smc-util-node/misc_node')28misc = require('smc-util/misc')29{defaults, required} = misc3031MAX_BLOB_SIZE = 1500000032MAX_BLOB_SIZE_HUMAN = "15MB"3334# save a blob in the blobstore database with given misc_node.uuidsha1 hash.35exports.save_blob = (opts) ->36opts = defaults opts,37uuid : undefined # uuid=sha1-based from blob; actually *required*, but instead of a traceback, get opts.cb(err)38blob : undefined # actually *required*, but instead of a traceback, get opts.cb(err)39ttl : undefined # object in blobstore will have *at least* this ttl in seconds;40# if there is already something, in blobstore with longer ttl, we leave it; undefined = infinite ttl41check : true # if true, return an error (via cb) if misc_node.uuidsha1(opts.blob) != opts.uuid.42# This is a check against bad user-supplied data.43project_id : undefined # also required44database : required45cb : required # cb(err, ttl actually used in seconds); ttl=0 for infinite ttl4647dbg = (m) -> winston.debug("save_blob(uuid=#{opts.uuid}): #{m}")48dbg()4950err = undefined5152if not opts.blob?53err = "save_blob: UG -- error in call to save_blob (uuid=#{opts.uuid}); received a save_blob request with undefined blob"5455else if not opts.uuid?56err = "save_blob: BUG -- error in call to save_blob; received a save_blob request without corresponding uuid"5758else if not opts.project_id?59err = "save_blob: BUG -- error in call to save_blob; received a save_blob request without corresponding project_id"6061else if opts.blob.length > MAX_BLOB_SIZE62err = "save_blob: blobs are limited to #{MAX_BLOB_SIZE_HUMAN} and you just tried to save one of size #{opts.blob.length/1000000}MB"6364else if opts.check and opts.uuid != misc_node.uuidsha1(opts.blob)65err = "save_blob: uuid=#{opts.uuid} must be derived from the Sha1 hash of blob, but it is not (possible malicious attack)"6667if err68dbg(err)69opts.cb(err)70return7172# Store the blob in the database, if it isn't there already.73opts.database.save_blob74uuid : opts.uuid75blob : opts.blob76ttl : opts.ttl77project_id : opts.project_id78cb : (err, ttl) =>79if err80dbg("failed to store blob -- #{err}")81else82dbg("successfully stored blob")83opts.cb(err, ttl)84858687