diff --git a/client/api/asset.js b/client/api/asset.js
index 2ca18bc65..6cb2af6c8 100644
--- a/client/api/asset.js
+++ b/client/api/asset.js
@@ -1,19 +1,33 @@
import request from './request';
const urls = {
- base: repositoryId => `/repositories/${repositoryId}/assets`
+ base: 'assets',
+ repository: repositoryId => `repositories/${repositoryId}/assets`
};
-function getUrl(repositoryId, key) {
+function getUrl(key) {
const params = { key };
- return request.get(urls.base(repositoryId), { params }).then(res => res.data.url);
+ return request.get(urls.base, { params }).then(res => res.data.url);
}
-function upload(repositoryId, data) {
- return request.post(urls.base(repositoryId), data).then(res => res.data);
+function upload(data) {
+ return request.post(urls.base, data).then(res => res.data);
+}
+
+function getRepositoryAssetUrl(repositoryId, key) {
+ const params = { key };
+ return request.get(urls.repository(repositoryId), { params })
+ .then(res => res.data.url);
+}
+
+function uploadRepositoryAsset(repositoryId, data) {
+ return request.post(urls.repository(repositoryId), data)
+ .then(res => res.data);
}
export default {
getUrl,
- upload
+ upload,
+ getRepositoryAssetUrl,
+ uploadRepositoryAsset
};
diff --git a/client/components/common/FileInput.vue b/client/components/common/FileInput.vue
index 4a902042a..eacafadfd 100644
--- a/client/components/common/FileInput.vue
+++ b/client/components/common/FileInput.vue
@@ -1,49 +1,56 @@
-
+
+
+
diff --git a/client/components/common/InputAsset.vue b/client/components/common/InputAsset.vue
index fc79b9ef9..5eda4867c 100644
--- a/client/components/common/InputAsset.vue
+++ b/client/components/common/InputAsset.vue
@@ -15,6 +15,7 @@
:uploading.sync="uploading"
:validate="{ ext: extensions }"
:confirm-deletion="false"
+ :repository-id="repositoryId"
:label="uploadLabel"
class="upload-btn" />
@@ -93,6 +94,7 @@ function isUploaded(url) {
export default {
name: 'input-asset',
props: {
+ repositoryId: { type: Number, default: null },
url: { type: String, default: null },
publicUrl: { type: String, default: null },
extensions: { type: Array, required: true },
diff --git a/client/components/common/mixins/upload.js b/client/components/common/UploadProvider.vue
similarity index 60%
rename from client/components/common/mixins/upload.js
rename to client/components/common/UploadProvider.vue
index 2da93b7e5..c29d8e9e3 100644
--- a/client/components/common/mixins/upload.js
+++ b/client/components/common/UploadProvider.vue
@@ -1,13 +1,21 @@
+
+
+
+
+
+
+;
diff --git a/client/components/common/tce-core/UploadBtn.vue b/client/components/common/tce-core/UploadBtn.vue
index d4ff98370..1e5bca687 100644
--- a/client/components/common/tce-core/UploadBtn.vue
+++ b/client/components/common/tce-core/UploadBtn.vue
@@ -1,5 +1,12 @@
-
+
-
+
diff --git a/client/components/content-elements/tce-audio/edit/Toolbar.vue b/client/components/content-elements/tce-audio/edit/Toolbar.vue
index 884cd32e1..b9b0d089c 100644
--- a/client/components/content-elements/tce-audio/edit/Toolbar.vue
+++ b/client/components/content-elements/tce-audio/edit/Toolbar.vue
@@ -6,6 +6,7 @@
Audio Component
Video component
{
+ const storage = getStorage(req.repository.id);
+ return middleware(storage)(req, res, next);
+ };
+}
diff --git a/server/repository/storage.js b/server/repository/storage.js
deleted file mode 100644
index 3eb088304..000000000
--- a/server/repository/storage.js
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict';
-
-const BaseStorage = require('../shared/storage');
-const config = require('../../config/server').storage;
-const path = require('path');
-
-class Storage extends BaseStorage {
- getPath(repositoryId) {
- return path.join('repository', `${repositoryId}`, config.path);
- }
-}
-
-module.exports = new Storage(config);
diff --git a/server/repository/proxy.js b/server/repository/storage/accessManager.js
similarity index 58%
rename from server/repository/proxy.js
rename to server/repository/storage/accessManager.js
index 161f85c71..23578facb 100644
--- a/server/repository/proxy.js
+++ b/server/repository/storage/accessManager.js
@@ -1,14 +1,15 @@
'use strict';
-const BaseProxy = require('../shared/storage/proxy');
-const { proxy: config } = require('../../config/server').storage;
+const AccessManager = require('../../shared/storage/proxy/AccessManager');
const path = require('path');
-const storageCookies = {
- REPOSITORY: 'Storage-Repository'
-};
+const storageCookies = { REPOSITORY: 'Storage-Repository' };
+
+class RepositoryStorageAccessManager extends AccessManager {
+ get cookies() {
+ return Object.values(storageCookies);
+ }
-class Proxy extends BaseProxy {
getSignedCookies(repositoryId, maxAge) {
const resource = path.join('repository', `${repositoryId}`);
return {
@@ -22,13 +23,6 @@ class Proxy extends BaseProxy {
const isRepositoryId = cookies[REPOSITORY] === repositoryId.toString();
return isRepositoryId && super.hasCookies(cookies);
}
-
- getCookieNames() {
- return [
- ...super.getCookieNames(),
- ...Object.values(storageCookies)
- ];
- }
}
-module.exports = new Proxy(config);
+module.exports = new RepositoryStorageAccessManager();
diff --git a/server/repository/storage/index.js b/server/repository/storage/index.js
new file mode 100644
index 000000000..b19c067c7
--- /dev/null
+++ b/server/repository/storage/index.js
@@ -0,0 +1,79 @@
+'use strict';
+
+const { storage: config } = require('../../../config/server');
+const path = require('path');
+const serviceProvider = require('../../shared/serviceProvider');
+const { Storage } = require('../../shared/storage');
+
+class RepositoryStorage extends Storage {
+ constructor(config, repositoryId) {
+ super(config);
+ this.repositoryId = repositoryId;
+ }
+
+ getFullKey(key) {
+ return path.join('repository', `${this.repositoryId}/${key}`);
+ }
+
+ getFile(key, options = {}) {
+ const fullKey = this.getFullKey(key);
+ return super.getFile(fullKey, options);
+ }
+
+ createReadStream(key, options = {}) {
+ const fullKey = this.getFullKey(key);
+ return super.createReadStream(fullKey, options);
+ }
+
+ saveFile(key, data, options = {}) {
+ const fullKey = this.getFullKey(key);
+ return super.saveFile(fullKey, data, options);
+ }
+
+ createWriteStream(key, options = {}) {
+ const fullKey = this.getFullKey(key);
+ return super.createWriteStream(fullKey, options);
+ }
+
+ copyFile(key, newKey) {
+ const fullKey = this.getFullKey(key);
+ const fullNewKey = this.getFullKey(newKey);
+ return super.copyFile(fullKey, fullNewKey);
+ }
+
+ moveFile(key, newKey) {
+ const fullKey = this.getFullKey(key);
+ const fullNewKey = this.getFullKey(newKey);
+ return super.moveFile(fullKey, fullNewKey);
+ }
+
+ deleteFile(key) {
+ const fullKey = this.getFullKey(key);
+ return super.deleteFile(fullKey);
+ }
+
+ deleteFiles(keys) {
+ const fullKeys = keys.map(key => this.getFullKey(key));
+ return Promise.map(fullKeys, key => this.deleteFile(key));
+ }
+
+ listFiles(key, options = {}) {
+ const fullKey = this.getFullKey(key);
+ return super.listFiles(fullKey, options);
+ }
+
+ fileExists(key) {
+ const fullKey = this.getFullKey(key);
+ return super.fileExists(fullKey);
+ }
+
+ getFileUrl(key) {
+ const fullKey = this.getFullKey(key);
+ return super.getFileUrl(fullKey);
+ }
+}
+
+const getRepositoryStorage = repositoryId => new RepositoryStorage(config, repositoryId);
+serviceProvider.set('repositoryStorage', getRepositoryStorage);
+
+module.exports = getRepositoryStorage;
diff --git a/server/router.js b/server/router.js
index 17d76631d..a8fcd28a5 100644
--- a/server/router.js
+++ b/server/router.js
@@ -2,13 +2,17 @@
const { auth: authConfig } = require('../config/server');
const { authenticate } = require('./shared/auth');
+const createStorageRouter = require('./shared/storage/storage.router');
const express = require('express');
const { extractAuthData } = require('./shared/auth/mw');
const repository = require('./repository');
+const serviceProvider = require('./shared/serviceProvider');
const tag = require('./tag');
const user = require('./user');
const router = express.Router();
+const storage = serviceProvider.get('storage');
+const storageRouter = createStorageRouter(storage);
router.use(processBody);
router.use(extractAuthData);
@@ -24,6 +28,7 @@ authConfig.oidc.enabled && (() => {
// Protected routes:
router.use(authenticate('jwt'));
router.use(repository.path, repository.router);
+router.use(storageRouter.path, storageRouter.router);
router.use(tag.path, tag.router);
module.exports = router;
diff --git a/server/script/detachDeletedRepos.js b/server/script/detachDeletedRepos.js
index 0934790bc..da9e07d7a 100644
--- a/server/script/detachDeletedRepos.js
+++ b/server/script/detachDeletedRepos.js
@@ -8,7 +8,7 @@ const each = require('lodash/each');
const find = require('lodash/find');
const omit = require('lodash/omit');
const { Repository } = require('../shared/database');
-const storage = require('../repository/storage');
+const storage = require('../shared/storage');
Repository.findAll({ paranoid: false })
.then(repositories => repositories.length && updateRepositoryCatalog(repositories))
diff --git a/server/shared/auth/authenticator.js b/server/shared/auth/authenticator.js
index 0f5686b6c..3c1b6a50d 100644
--- a/server/shared/auth/authenticator.js
+++ b/server/shared/auth/authenticator.js
@@ -6,8 +6,8 @@ const { Authenticator } = require('passport');
const autobind = require('auto-bind');
const { auth: config } = require('../../../config/server');
const { IncomingMessage } = require('http');
-const storageProxy = require('../../repository/proxy');
const isFunction = arg => typeof arg === 'function';
+const serviceProvider = require('../serviceProvider');
class Auth extends Authenticator {
constructor() {
@@ -56,10 +56,11 @@ class Auth extends Authenticator {
}
logout({ middleware = false } = {}) {
- const storageCookies = storageProxy.getCookieNames();
return (_, res, next) => {
res.clearCookie(config.jwt.cookie.name);
res.clearCookie('auth');
+ const storageProxy = serviceProvider.get('storageProxy');
+ const storageCookies = storageProxy.getCookieNames();
storageCookies.forEach(name => res.clearCookie(name));
return middleware ? next() : res.end();
};
diff --git a/server/shared/content-plugins/elementRegistry.js b/server/shared/content-plugins/elementRegistry.js
index 83b76b422..a13c56794 100644
--- a/server/shared/content-plugins/elementRegistry.js
+++ b/server/shared/content-plugins/elementRegistry.js
@@ -5,10 +5,10 @@ const config = require('../../../config/server');
const dedent = require('dedent');
const depd = require('depd');
const elementsList = require('../../../config/shared/core-elements');
+const getRepositoryStorage = require('../../repository/storage');
const hooks = require('./elementHooks');
const pick = require('lodash/pick');
-const storage = require('../../repository/storage');
-const storageProxy = require('../../repository/proxy');
+const serviceProvider = require('../../shared/serviceProvider');
const toCase = require('to-case');
const EXTENSIONS_LIST = '../../../extensions/content-elements/index';
@@ -37,7 +37,9 @@ class ElementsRegistry extends BaseRegistry {
getHook(type, hook) {
const elementHooks = this._hooks[type];
if (!elementHooks || !elementHooks[hook]) return;
- const services = { config, storage, storageProxy };
+ const storageProxy = serviceProvider.get('storageProxy');
+ const storage = serviceProvider.get('storage');
+ const services = { config, storageProxy, storage, getRepositoryStorage };
return (element, options) => elementHooks[hook](element, services, options);
}
diff --git a/server/shared/publishing/helpers.js b/server/shared/publishing/helpers.js
index df1f47c00..fecbbc162 100644
--- a/server/shared/publishing/helpers.js
+++ b/server/shared/publishing/helpers.js
@@ -25,7 +25,7 @@ const pick = require('lodash/pick');
const Promise = require('bluebird');
const reduce = require('lodash/reduce');
const { resolveStatics } = require('../storage/helpers');
-const storage = require('../../repository/storage');
+const storage = require('../storage');
const without = require('lodash/without');
const { FLAT_REPO_STRUCTURE } = process.env;
diff --git a/server/shared/serviceProvider.js b/server/shared/serviceProvider.js
new file mode 100644
index 000000000..27743330f
--- /dev/null
+++ b/server/shared/serviceProvider.js
@@ -0,0 +1,20 @@
+'use strict';
+
+const isFunction = require('lodash/isFunction');
+
+function serviceProvider() {
+ const services = {};
+
+ const get = (key, ...params) => {
+ const service = services[key];
+ if (isFunction(service)) return service(...params);
+ return service;
+ };
+ const set = (key, service) => {
+ services[key] = service;
+ };
+
+ return { get, set };
+}
+
+module.exports = serviceProvider();
diff --git a/server/shared/storage/helpers.js b/server/shared/storage/helpers.js
index b21c99804..9d4799a2a 100644
--- a/server/shared/storage/helpers.js
+++ b/server/shared/storage/helpers.js
@@ -4,7 +4,7 @@ const { elementRegistry } = require('../content-plugins');
const get = require('lodash/get');
const config = require('../../../config/server').storage;
const Promise = require('bluebird');
-const proxy = require('../../repository/proxy');
+const serviceProvider = require('../../shared/serviceProvider');
const set = require('lodash/set');
const toPairs = require('lodash/toPairs');
const values = require('lodash/values');
@@ -31,8 +31,11 @@ async function resolveAssetsMap(element) {
await Promise.map(toPairs(element.data.assets), ([key, url]) => {
if (!url) return set(element.data, key, url);
const isStorageResource = url.startsWith(config.protocol);
+ const proxy = serviceProvider.get('storageProxy');
+ const storage = serviceProvider.get('repositoryStorage', element.repositoryId);
+ const fullKey = storage.getFullKey(url.substr(config.protocol.length, url.length));
const resolvedUrl = isStorageResource
- ? proxy.getFileUrl(url.substr(config.protocol.length, url.length))
+ ? proxy.getFileUrl(fullKey)
: url;
set(element.data, key, resolvedUrl);
});
diff --git a/server/shared/storage/index.js b/server/shared/storage/index.js
index e66ed028f..5a7b9aae0 100644
--- a/server/shared/storage/index.js
+++ b/server/shared/storage/index.js
@@ -66,7 +66,8 @@ class Storage {
}
}
-module.exports = Storage;
+module.exports = config => new Storage(config);
+module.exports.Storage = Storage;
function loadProvider(name) {
try {
diff --git a/server/shared/storage/proxy/AccessManager.js b/server/shared/storage/proxy/AccessManager.js
new file mode 100644
index 000000000..8c00f8f46
--- /dev/null
+++ b/server/shared/storage/proxy/AccessManager.js
@@ -0,0 +1,25 @@
+'use strict';
+
+const serviceProvider = require('../../serviceProvider');
+
+class AccessManager {
+ constructor() {
+ const proxy = serviceProvider.get('storageProxy');
+ this._instance = proxy.createAccessManager();
+ proxy.registerAccessManager(this);
+ }
+
+ get cookies() {
+ return {};
+ }
+
+ hasCookies(cookies) {
+ return this._instance.hasCookies(cookies);
+ }
+
+ getSignedCookies(resource, maxAge) {
+ return this._instance.getSignedCookies(resource, maxAge);
+ }
+}
+
+module.exports = AccessManager;
diff --git a/server/shared/storage/proxy/index.js b/server/shared/storage/proxy/index.js
index 652815d32..fda05b295 100644
--- a/server/shared/storage/proxy/index.js
+++ b/server/shared/storage/proxy/index.js
@@ -1,11 +1,15 @@
'use strict';
const autobind = require('auto-bind');
+const flatMap = require('lodash/flatMap');
const path = require('path');
+const uniq = require('lodash/uniq');
class Proxy {
constructor(config) {
+ this.storages = {};
this.provider = Proxy.createProvider(config);
+ this.accessManagers = [this.provider.accessManager];
autobind(this);
}
@@ -26,28 +30,47 @@ class Proxy {
return this.isSelfHosted && this.provider.path;
}
- getSignedCookies(resource, maxAge) {
- return this.provider.getSignedCookies(resource, maxAge);
+ addStorage(path, storage) {
+ const existing = this.storages[path];
+ if (existing) throw new Error(`Storage is already mounted on ${path} path.`);
+ this.storages[path] = storage;
}
- verifyCookies(cookies, resource) {
- return this.provider.verifyCookies(cookies, resource);
+ registerAccessManager(manager) {
+ this.accessManagers.push(manager);
}
- hasCookies(cookies) {
- return this.provider.hasCookies(cookies);
+ getStorage(key) {
+ const path = Object.keys(this.storages)
+ .sort(compareStringsByLengthDesc)
+ .find(path => key.startsWith(path));
+
+ return path && this.storages[path];
+ }
+
+ createReadStream(key) {
+ const storage = this.getStorage(key);
+ return storage.createReadStream(key);
}
getFileUrl(key) {
return this.provider.getFileUrl(key);
}
+ createAccessManager() {
+ return Object.create(this.provider.accessManager);
+ }
+
+ verifyCookies(cookies, key) {
+ return this.provider.accessManager.verifyCookies(cookies, key);
+ }
+
getCookieNames() {
- return this.provider.getCookieNames();
+ return uniq(flatMap(this.accessManagers, 'cookies'));
}
}
-module.exports = Proxy;
+module.exports = (config, storage) => new Proxy(config, storage);
function loadProvider(name) {
try {
@@ -57,3 +80,7 @@ function loadProvider(name) {
throw err;
}
}
+
+function compareStringsByLengthDesc(fst, sec) {
+ return sec.length - fst.length;
+}
diff --git a/server/shared/storage/proxy/mw.js b/server/shared/storage/proxy/mw.js
index ca46aaca3..ab181bdeb 100644
--- a/server/shared/storage/proxy/mw.js
+++ b/server/shared/storage/proxy/mw.js
@@ -5,28 +5,30 @@ const miss = require('mississippi');
const path = require('path');
const router = require('express').Router();
-module.exports = (storage, proxy) => {
- function getFile(req, res, next) {
+function getFile(proxy) {
+ return router.get('/*', (req, res, next) => {
const key = req.params[0];
const hasValidCookies = proxy.verifyCookies(req.cookies, key);
if (!hasValidCookies) return res.status(FORBIDDEN).end();
res.type(path.extname(key));
- miss.pipe(storage.createReadStream(key), res, err => {
+ miss.pipe(proxy.createReadStream(key), res, err => {
if (err) return next(err);
res.end();
});
- }
+ });
+}
- function setSignedCookies(req, res, next) {
+function setSignedCookies(accessManager) {
+ return (req, res, next) => {
const repositoryId = req.repository.id;
- if (proxy.hasCookies(req.cookies, repositoryId)) return next();
+ if (accessManager.hasCookies(req.cookies, repositoryId)) return next();
const maxAge = 1000 * 60 * 60; // 1 hour in ms
- const cookies = proxy.getSignedCookies(repositoryId, maxAge);
+ const cookies = accessManager.getSignedCookies(repositoryId, maxAge);
Object.entries(cookies).forEach(([cookie, value]) => {
res.cookie(cookie, value, { maxAge, httpOnly: true });
});
next();
- }
+ };
+}
- return { proxy: router.get('/*', getFile), setSignedCookies };
-};
+module.exports = { getFile, setSignedCookies };
diff --git a/server/shared/storage/proxy/providers/cloudfront/AccessManager.js b/server/shared/storage/proxy/providers/cloudfront/AccessManager.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/server/shared/storage/proxy/providers/cloudfront.js b/server/shared/storage/proxy/providers/cloudfront/index.js
similarity index 100%
rename from server/shared/storage/proxy/providers/cloudfront.js
rename to server/shared/storage/proxy/providers/cloudfront/index.js
diff --git a/server/shared/storage/proxy/providers/local.js b/server/shared/storage/proxy/providers/local/AccessManager.js
similarity index 66%
rename from server/shared/storage/proxy/providers/local.js
rename to server/shared/storage/proxy/providers/local/AccessManager.js
index 0086993c1..abe75d587 100644
--- a/server/shared/storage/proxy/providers/local.js
+++ b/server/shared/storage/proxy/providers/local/AccessManager.js
@@ -2,32 +2,19 @@
const every = require('lodash/every');
const NodeRSA = require('node-rsa');
-const { origin } = require('../../../../../config/server');
-const urlJoin = require('url-join');
-const { validateConfig } = require('../../validation');
-const yup = require('yup');
-const PROXY_PATH = '/proxy';
const storageCookies = {
SIGNATURE: 'Storage-Signature',
EXPIRES: 'Storage-Expires'
};
-const schema = yup.object().shape({
- privateKey: yup.string().pkcs1().required()
-});
-
-class Local {
+class LocalAccessManager {
constructor(config) {
- config = validateConfig(config, schema);
-
this.signer = new NodeRSA(config.privateKey, 'private');
- this.isSelfHosted = true;
- this.path = PROXY_PATH;
}
- static create(config) {
- return new this(config);
+ get cookies() {
+ return Object.values(storageCookies);
}
getSignedCookies(resource, maxAge) {
@@ -51,17 +38,9 @@ class Local {
hasCookies(cookies) {
return every(storageCookies, cookie => cookies[cookie]);
}
-
- getFileUrl(key) {
- return urlJoin(origin, this.path, key);
- }
-
- getCookieNames() {
- return Object.values(storageCookies);
- }
}
-module.exports = { create: Local.create.bind(Local) };
+module.exports = LocalAccessManager;
function getExpirationTime(maxAge) {
// Expiration unix timestamp in ms
diff --git a/server/shared/storage/proxy/providers/local/index.js b/server/shared/storage/proxy/providers/local/index.js
new file mode 100644
index 000000000..6e5dd2b7d
--- /dev/null
+++ b/server/shared/storage/proxy/providers/local/index.js
@@ -0,0 +1,32 @@
+'use strict';
+
+const AccessManager = require('./AccessManager');
+const { origin } = require('../../../../../../config/server');
+const urlJoin = require('url-join');
+const { validateConfig } = require('../../../validation');
+const yup = require('yup');
+
+const PROXY_PATH = '/proxy';
+
+const schema = yup.object().shape({
+ privateKey: yup.string().pkcs1().required()
+});
+
+class Local {
+ constructor(config) {
+ config = validateConfig(config, schema);
+ this.accessManager = new AccessManager(config);
+ this.isSelfHosted = true;
+ this.path = PROXY_PATH;
+ }
+
+ static create(config) {
+ return new this(config);
+ }
+
+ getFileUrl(key) {
+ return urlJoin(origin, this.path, key);
+ }
+}
+
+module.exports = { create: Local.create.bind(Local) };
diff --git a/server/shared/storage/storage.controller.js b/server/shared/storage/storage.controller.js
index 5310c48e3..381693640 100644
--- a/server/shared/storage/storage.controller.js
+++ b/server/shared/storage/storage.controller.js
@@ -1,6 +1,5 @@
'use strict';
-const { getFileUrl, getPath, saveFile } = require('../../repository/storage');
const { readFile, sha256 } = require('./util');
const config = require('../../../config/server').storage;
const fecha = require('fecha');
@@ -12,46 +11,52 @@ const pickBy = require('lodash/pickBy');
const getStorageUrl = key => `${config.protocol}${key}`;
-function getUrl(req, res) {
- const { query: { key } } = req;
- return getFileUrl(key).then(url => res.json({ url }));
+function getUrl(storage) {
+ return (req, res) => {
+ const { query: { key } } = req;
+ return storage.getFileUrl(key).then(url => res.json({ url }));
+ };
}
-async function upload({ file, body, user, repository }, res) {
- const { name } = path.parse(file.originalname);
- const { id: repositoryId } = repository;
- if (body.unpack) {
- const timestamp = fecha.format(new Date(), 'YYYY-MM-DDTHH:mm:ss');
- const root = `${timestamp}__${user.id}__${name}`;
- const assets = await uploadArchiveContent(repositoryId, file, root);
- return res.json({ root, assets });
- }
- const asset = await uploadFile(repositoryId, file, name);
- return res.json(asset);
+function upload(storage) {
+ return async (req, res) => {
+ const { file, body, user } = req;
+ const { name } = path.parse(file.originalname);
+ if (body.unpack) {
+ const timestamp = fecha.format(new Date(), 'YYYY-MM-DDTHH:mm:ss');
+ const root = `${timestamp}__${user.id}__${name}`;
+ const assets = await uploadArchiveContent(storage, file, root);
+ return res.json({ root, assets });
+ }
+ const asset = await uploadFile(storage, file, name);
+ return res.json(asset);
+ };
}
module.exports = { getUrl, upload };
-async function uploadFile(repositoryId, file, name) {
+async function uploadFile(storage, file, name) {
const buffer = await readFile(file);
const hash = sha256(file.originalname, buffer);
const extension = path.extname(file.originalname);
- const fileName = `${hash}___${name}${extension}`;
- const key = path.join(getPath(repositoryId), fileName);
- await saveFile(key, buffer, { ContentType: file.mimetype });
- const publicUrl = await getFileUrl(key);
+ const key = `${hash}___${name}${extension}`;
+ await storage.saveFile(key, buffer, { ContentType: file.mimetype });
+ const publicUrl = await storage.getFileUrl(key);
return { key, publicUrl, url: getStorageUrl(key) };
}
-async function uploadArchiveContent(repositoryId, archive, name) {
+async function uploadArchiveContent(storage, archive, name) {
const buffer = await readFile(archive);
const content = await JSZip.loadAsync(buffer);
const files = pickBy(content.files, it => !it.dir);
const keys = await Promise.all(Object.keys(files).map(async src => {
- const key = path.join(getPath(repositoryId), name, src);
+ const keyComponents = [name, src].filter(Boolean);
+ const key = path.join(...keyComponents);
const file = await content.file(src).async('uint8array');
const mimeType = mime.lookup(src);
- await saveFile(key, Buffer.from(file), { ContentType: mimeType });
+ await storage.saveFile(key, Buffer.from(file), {
+ ContentType: mimeType
+ });
return [key, getStorageUrl(key)];
}));
return fromPairs(keys);
diff --git a/server/shared/storage/storage.router.js b/server/shared/storage/storage.router.js
index d2ba00d5a..dec70e46c 100644
--- a/server/shared/storage/storage.router.js
+++ b/server/shared/storage/storage.router.js
@@ -1,28 +1,18 @@
'use strict';
-const { createError } = require('../error/helpers');
const ctrl = require('./storage.controller');
-const { FORBIDDEN } = require('http-status-codes');
const multer = require('multer');
const router = require('express').Router();
-const storage = require('../../repository/storage');
const upload = multer({ storage: multer.memoryStorage() });
-router
- .get('/', validateAssetRepository, ctrl.getUrl)
- .post('/', upload.single('file'), ctrl.upload);
-
-function validateAssetRepository(req, res, next) {
- const { repository, query: { key } } = req;
- const repositoryAssetsPath = storage.getPath(repository.id);
- if (!key.startsWith(repositoryAssetsPath)) {
- return createError(FORBIDDEN, 'Access restricted');
- }
- next();
+function createRouter(storage) {
+ return router
+ .get('/', ctrl.getUrl(storage))
+ .post('/', upload.single('file'), ctrl.upload(storage));
}
-module.exports = {
+module.exports = storage => ({
path: '/assets',
- router
-};
+ router: createRouter(storage)
+});
diff --git a/server/shared/transfer/default/index.js b/server/shared/transfer/default/index.js
index e330d3199..322df2d93 100644
--- a/server/shared/transfer/default/index.js
+++ b/server/shared/transfer/default/index.js
@@ -4,7 +4,7 @@ const processors = require('./processors');
const Promise = require('bluebird');
const resolvers = require('./resolvers');
const { sequelize } = require('../../database');
-const storage = require('../../../repository/storage');
+const storage = require('../../storage');
const { useTar } = require('../formats');
const yup = require('yup');