|
@@ -11,6 +11,7 @@ import { hashFile } from '../../../services/helpers/hashing'
|
|
|
import { createNonce, getTokenExpirationTime } from '../../../services/helpers/tokenNonceKeeper'
|
|
|
import { getFileInfo } from '../../../services/helpers/fileInfo'
|
|
|
import { parseBagId } from '../../helpers/bagTypes'
|
|
|
+import { BagId } from '@joystream/types/storage'
|
|
|
import logger from '../../../services/logger'
|
|
|
import { KeyringPair } from '@polkadot/keyring/types'
|
|
|
import { ApiPromise } from '@polkadot/api'
|
|
@@ -19,6 +20,7 @@ import fs from 'fs'
|
|
|
import path from 'path'
|
|
|
import send from 'send'
|
|
|
import { CLIError } from '@oclif/errors'
|
|
|
+import { hexToString } from '@polkadot/util'
|
|
|
const fsPromises = fs.promises
|
|
|
|
|
|
/**
|
|
@@ -107,10 +109,14 @@ export async function uploadFile(req: express.Request, res: express.Response): P
|
|
|
const fileObj = getFileObject(req)
|
|
|
cleanupFileName = fileObj.path
|
|
|
|
|
|
- verifyFileSize(fileObj.size)
|
|
|
+ const api = getApi(res)
|
|
|
+ await verifyFileSize(api, fileObj.size)
|
|
|
await verifyFileMimeType(fileObj.path)
|
|
|
|
|
|
const hash = await hashFile(fileObj.path)
|
|
|
+ const bagId = parseBagId(api, uploadRequest.bagId)
|
|
|
+
|
|
|
+ await verifyDataObjectInfo(api, bagId, uploadRequest.dataObjectId, fileObj.size, hash)
|
|
|
|
|
|
// Prepare new file name
|
|
|
const newPath = fileObj.path.replace(fileObj.filename, hash)
|
|
@@ -119,8 +125,6 @@ export async function uploadFile(req: express.Request, res: express.Response): P
|
|
|
await fsPromises.rename(fileObj.path, newPath)
|
|
|
cleanupFileName = newPath
|
|
|
|
|
|
- const api = getApi(res)
|
|
|
- const bagId = parseBagId(api, uploadRequest.bagId)
|
|
|
await acceptPendingDataObjects(api, bagId, getAccount(res), getWorkerId(res), uploadRequest.storageBucketId, [
|
|
|
uploadRequest.dataObjectId,
|
|
|
])
|
|
@@ -296,17 +300,55 @@ async function validateTokenRequest(api: ApiPromise, tokenRequest: UploadTokenRe
|
|
|
/**
|
|
|
* Validates file size. It throws an error when file size exceeds the limit
|
|
|
*
|
|
|
- * @param fileSize - runtime API promise
|
|
|
+ * @param api - runtime API promise
|
|
|
+ * @param fileSize - file size to validate
|
|
|
* @returns void promise.
|
|
|
*/
|
|
|
-function verifyFileSize(fileSize: number) {
|
|
|
- const MAX_FILE_SIZE = 1000000 // TODO: Get this const from the runtime
|
|
|
+async function verifyFileSize(api: ApiPromise, fileSize: number) {
|
|
|
+ const maxRuntimeFileSize = await api.consts.storage.maxDataObjectSize.toNumber()
|
|
|
|
|
|
- if (fileSize > MAX_FILE_SIZE) {
|
|
|
+ if (fileSize > maxRuntimeFileSize) {
|
|
|
throw new WebApiError('Max file size exceeded.', 400)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Validates the runtime info for the data object. It verifies contentID,
|
|
|
+ * file size, and 'accepted' status.
|
|
|
+ *
|
|
|
+ * @param api - runtime API promise
|
|
|
+ * @param bagId - bag ID
|
|
|
+ * @param dataObjectId - data object ID to validate in runtime
|
|
|
+ * @param fileSize - file size to validate
|
|
|
+ * @param hash - file multihash
|
|
|
+ * @returns void promise.
|
|
|
+ */
|
|
|
+async function verifyDataObjectInfo(
|
|
|
+ api: ApiPromise,
|
|
|
+ bagId: BagId,
|
|
|
+ dataObjectId: number,
|
|
|
+ fileSize: number,
|
|
|
+ hash: string
|
|
|
+) {
|
|
|
+ const dataObject = await api.query.storage.dataObjectsById(bagId, dataObjectId)
|
|
|
+
|
|
|
+ if (dataObject.accepted.valueOf()) {
|
|
|
+ throw new WebApiError(`Data object had been already accepted ID = ${dataObjectId}`, 400)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dataObject.get('size').toNumber() !== fileSize) {
|
|
|
+ throw new WebApiError(`File size doesn't match the data object's size for data object ID = ${dataObjectId}`, 400)
|
|
|
+ }
|
|
|
+
|
|
|
+ const runtimeHash = hexToString(dataObject.ipfsContentId.toString())
|
|
|
+ if (runtimeHash !== hash) {
|
|
|
+ throw new WebApiError(
|
|
|
+ `File multihash doesn't match the data object's ipfsContentId for data object ID = ${dataObjectId}`,
|
|
|
+ 400
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Tries to remove file on error. It silences possible IO error and logs it.
|
|
|
*
|