feat: private content (#1137)

* save images as private and serve via signed url from images.info api

* download private images to directory on export

* fix lint errors

* private s3 default, AWS.s3 module level scope, default s3 url expiry

* combine regex to one, and only replace when there are matches

* fix lint

* code not needed anymore, remove

* updates after pulling master

* revert the uploadToS3FromUrl url return

* use model gettr to compact code, rename to attachments api

* basic checking of document read permission to allow attachment viewing

* fix: Continue to upload avatars as public
fix: Allow redirect for non-private attachments

* add support for publicly shared documents

* catch errors which crash the app during zip export and user creation

* add tests

* enable AWS signature v4 for s3

* switch to use factories to build models for testing

* add isDocker flag for local serving of attachment redirect url

* fix redirect tests

Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
Huss
2020-02-13 03:40:44 +00:00
committed by GitHub
parent 064d8cea44
commit 8e2b19dc7a
15 changed files with 316 additions and 39 deletions

View File

@@ -17,6 +17,7 @@ import userInviter from '../commands/userInviter';
import { presentUser } from '../presenters';
import policy from '../policies';
const AWS_S3_ACL = process.env.AWS_S3_ACL || 'private';
const { authorize } = policy;
const router = new Router();
@@ -61,12 +62,9 @@ router.post('users.info', auth(), async ctx => {
router.post('users.update', auth(), async ctx => {
const { user } = ctx.state;
const { name, avatarUrl } = ctx.body;
const endpoint = publicS3Endpoint();
if (name) user.name = name;
if (avatarUrl && avatarUrl.startsWith(`${endpoint}/uploads/${user.id}`)) {
user.avatarUrl = avatarUrl;
}
if (avatarUrl) user.avatarUrl = avatarUrl;
await user.save();
@@ -89,14 +87,19 @@ router.post('users.s3Upload', auth(), async ctx => {
const { user } = ctx.state;
const s3Key = uuid.v4();
const key = `uploads/${user.id}/${s3Key}/${name}`;
const acl =
ctx.body.public === undefined
? AWS_S3_ACL
: ctx.body.public ? 'public-read' : 'private';
const credential = makeCredential();
const longDate = format(new Date(), 'YYYYMMDDTHHmmss\\Z');
const policy = makePolicy(credential, longDate);
const policy = makePolicy(credential, longDate, acl);
const endpoint = publicS3Endpoint();
const url = `${endpoint}/${key}`;
await Attachment.create({
const attachment = await Attachment.create({
key,
acl,
size,
url,
contentType,
@@ -120,7 +123,7 @@ router.post('users.s3Upload', auth(), async ctx => {
form: {
'Cache-Control': 'max-age=31557600',
'Content-Type': contentType,
acl: 'public-read',
acl,
key,
policy,
'x-amz-algorithm': 'AWS4-HMAC-SHA256',
@@ -131,7 +134,7 @@ router.post('users.s3Upload', auth(), async ctx => {
asset: {
contentType,
name,
url,
url: attachment.redirectUrl,
size,
},
},