Skip to content

Commit 88f4228

Browse files
committed
Decouple local access manager from proxy 🚧
1 parent 28b1e0a commit 88f4228

File tree

10 files changed

+93
-51
lines changed

10 files changed

+93
-51
lines changed

‎server/app.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const helmet = require('helmet');
88
const origin = require('./shared/origin');
99
const path = require('path');
1010
const storage = require('./repository/storage');
11-
const storageProxy = require('./repository/proxy');
11+
const storageProxy = require('./shared/storage/proxy');
1212
// eslint-disable-next-line require-sort/require-sort
1313
require('express-async-errors');
1414

‎server/repository/index.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ const feed = require('./feed');
88
const multer = require('multer');
99
const path = require('path');
1010
const processQuery = require('../shared/util/processListQuery');
11-
const proxy = require('./proxy');
11+
const proxyAccessManager = require('./proxy');
1212
const { Repository } = require('../shared/database');
1313
const router = require('express').Router();
1414
const storage = require('./storage');
15-
const { setSignedCookies } = require('../shared/storage/proxy/mw')(storage, proxy);
15+
const { setSignedCookies } = require('../shared/storage/proxy/mw')(storage, proxyAccessManager);
1616

1717
/* eslint-disable require-sort/require-sort */
1818
const activity = require('../activity');

‎server/repository/proxy.js‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
'use strict';
22

3-
const BaseProxy = require('../shared/storage/proxy');
4-
const { proxy: config } = require('../../config/server').storage;
53
const path = require('path');
4+
const proxy = require('../shared/storage/proxy');
65

76
const storageCookies = {
87
REPOSITORY: 'Storage-Repository'
98
};
109

11-
class Proxy extends BaseProxy {
10+
class RepositoryProxyAccessManager extends proxy.AccessManager {
1211
getSignedCookies(repositoryId, maxAge) {
1312
const resource = path.join('repository', `${repositoryId}`);
1413
return {
@@ -31,4 +30,4 @@ class Proxy extends BaseProxy {
3130
}
3231
}
3332

34-
module.exports = new Proxy(config);
33+
module.exports = new RepositoryProxyAccessManager(proxy.config);

‎server/shared/content-plugins/elementRegistry.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const elementsList = require('../../../config/shared/core-elements');
88
const hooks = require('./elementHooks');
99
const pick = require('lodash/pick');
1010
const storage = require('../../repository/storage');
11-
const storageProxy = require('../../repository/proxy');
11+
const storageProxy = require('../../shared/storage/proxy');
1212
const toCase = require('to-case');
1313

1414
const EXTENSIONS_LIST = '../../../extensions/content-elements/index';

‎server/shared/storage/proxy/index.js‎

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const autobind = require('auto-bind');
44
const path = require('path');
5+
const { proxy: config } = require('../../../../config/server').storage;
56

67
class Proxy {
78
constructor(config) {
@@ -22,32 +23,40 @@ class Proxy {
2223
return this.provider.isSelfHosted;
2324
}
2425

26+
get config() {
27+
return this.provider.config;
28+
}
29+
2530
get path() {
2631
return this.isSelfHosted && this.provider.path;
2732
}
2833

29-
getSignedCookies(resource, maxAge) {
30-
return this.provider.getSignedCookies(resource, maxAge);
34+
get AccessManager() {
35+
return this.provider.AccessManager;
36+
}
37+
38+
getSignedCookies(resource, maxAge, accessManager) {
39+
return this.provider.getSignedCookies(resource, maxAge, accessManager);
3140
}
3241

33-
verifyCookies(cookies, resource) {
34-
return this.provider.verifyCookies(cookies, resource);
42+
verifyCookies(cookies, resource, accessManager) {
43+
return this.provider.verifyCookies(cookies, resource, accessManager);
3544
}
3645

37-
hasCookies(cookies) {
38-
return this.provider.hasCookies(cookies);
46+
hasCookies(cookies, ...params) {
47+
return this.provider.hasCookies(cookies, ...params);
3948
}
4049

4150
getFileUrl(key) {
4251
return this.provider.getFileUrl(key);
4352
}
4453

45-
getCookieNames() {
46-
return this.provider.getCookieNames();
54+
getCookieNames(accessManager) {
55+
return this.provider.getCookieNames(accessManager);
4756
}
4857
}
4958

50-
module.exports = Proxy;
59+
module.exports = new Proxy(config);
5160

5261
function loadProvider(name) {
5362
try {

‎server/shared/storage/proxy/mw.js‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
const { FORBIDDEN } = require('http-status-codes');
44
const miss = require('mississippi');
55
const path = require('path');
6+
const proxy = require('.');
67
const router = require('express').Router();
78

8-
module.exports = (storage, proxy) => {
9+
module.exports = (storage, proxyAccessManager) => {
910
function getFile(req, res, next) {
1011
const key = req.params[0];
11-
const hasValidCookies = proxy.verifyCookies(req.cookies, key);
12+
const hasValidCookies = proxy.verifyCookies(req.cookies, key, proxyAccessManager);
1213
if (!hasValidCookies) return res.status(FORBIDDEN).end();
1314
res.type(path.extname(key));
1415
miss.pipe(storage.createReadStream(key), res, err => {
@@ -19,9 +20,9 @@ module.exports = (storage, proxy) => {
1920

2021
function setSignedCookies(req, res, next) {
2122
const repositoryId = req.repository.id;
22-
if (proxy.hasCookies(req.cookies, repositoryId)) return next();
23+
if (proxy.hasCookies(req.cookies, repositoryId, proxyAccessManager)) return next();
2324
const maxAge = 1000 * 60 * 60; // 1 hour in ms
24-
const cookies = proxy.getSignedCookies(repositoryId, maxAge);
25+
const cookies = proxy.getSignedCookies(repositoryId, maxAge, proxyAccessManager);
2526
Object.entries(cookies).forEach(([cookie, value]) => {
2627
res.cookie(cookie, value, { maxAge, httpOnly: true });
2728
});

‎server/shared/storage/proxy/providers/cloudfront/access-manager.js‎

Whitespace-only changes.

‎server/shared/storage/proxy/providers/local.js‎ renamed to ‎server/shared/storage/proxy/providers/local/access-manager.js‎

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,18 @@
22

33
const every = require('lodash/every');
44
const NodeRSA = require('node-rsa');
5-
const { origin } = require('../../../../../config/server');
6-
const urlJoin = require('url-join');
7-
const { validateConfig } = require('../../validation');
8-
const yup = require('yup');
95

10-
const PROXY_PATH = '/proxy';
116
const storageCookies = {
127
SIGNATURE: 'Storage-Signature',
138
EXPIRES: 'Storage-Expires'
149
};
1510

16-
const schema = yup.object().shape({
17-
privateKey: yup.string().pkcs1().required()
18-
});
19-
20-
class Local {
11+
class LocalAccessManager {
2112
constructor(config) {
22-
config = validateConfig(config, schema);
23-
2413
this.signer = new NodeRSA(config.privateKey, 'private');
25-
this.isSelfHosted = true;
26-
this.path = PROXY_PATH;
27-
}
28-
29-
static create(config) {
30-
return new this(config);
3114
}
3215

33-
getSignedCookies(resource, maxAge) {
34-
const expires = getExpirationTime(maxAge);
16+
getSignedCookies(resource, expires) {
3517
const signature = this.signer.encrypt({ resource, expires }, 'base64');
3618
return {
3719
[storageCookies.SIGNATURE]: signature,
@@ -52,18 +34,9 @@ class Local {
5234
return every(storageCookies, cookie => cookies[cookie]);
5335
}
5436

55-
getFileUrl(key) {
56-
return urlJoin(origin, this.path, key);
57-
}
58-
5937
getCookieNames() {
6038
return Object.values(storageCookies);
6139
}
6240
}
6341

64-
module.exports = { create: Local.create.bind(Local) };
65-
66-
function getExpirationTime(maxAge) {
67-
// Expiration unix timestamp in ms
68-
return new Date().getTime() + maxAge;
69-
}
42+
module.exports = LocalAccessManager;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
'use strict';
2+
3+
const AccessManager = require('./access-manager');
4+
const last = require('lodash/last');
5+
const { origin } = require('../../../../../../config/server');
6+
const urlJoin = require('url-join');
7+
const { validateConfig } = require('../../../validation');
8+
const yup = require('yup');
9+
10+
const PROXY_PATH = '/proxy';
11+
12+
const schema = yup.object().shape({
13+
privateKey: yup.string().pkcs1().required()
14+
});
15+
16+
class Local {
17+
constructor(config) {
18+
this.config = validateConfig(config, schema);
19+
this.accessManager = new AccessManager(this.config);
20+
this.isSelfHosted = true;
21+
this.path = PROXY_PATH;
22+
}
23+
24+
static create(config) {
25+
return new this(config);
26+
}
27+
28+
get AccessManager() {
29+
return AccessManager;
30+
}
31+
32+
getSignedCookies(resource, maxAge, accessManager = this.accessManager) {
33+
const expires = getExpirationTime(maxAge);
34+
return accessManager.getSignedCookies(resource, expires);
35+
}
36+
37+
verifyCookies(cookies, key, accessManager = this.accessManager) {
38+
return accessManager.verifyCookies(cookies, key);
39+
}
40+
41+
hasCookies(cookies, ...params) {
42+
const accessManager = last(params) || this.accessManager;
43+
return accessManager.hasCookies(cookies, ...params);
44+
}
45+
46+
getCookieNames(accessManager = this.accessManager) {
47+
return accessManager.getCookieNames();
48+
}
49+
50+
getFileUrl(key) {
51+
return urlJoin(origin, this.path, key);
52+
}
53+
}
54+
55+
module.exports = { create: Local.create.bind(Local) };
56+
57+
function getExpirationTime(maxAge) {
58+
// Expiration unix timestamp in ms
59+
return new Date().getTime() + maxAge;
60+
}

0 commit comments

Comments
 (0)