a few changes to make A/B testing easier

This commit is contained in:
Danny Coates 2017-08-24 14:54:02 -07:00
parent b2f76d2df9
commit 53e822964e
No known key found for this signature in database
GPG key ID: 4C442633C62E00CB
94 changed files with 4566 additions and 3958 deletions

13
server/dev.js Normal file
View file

@ -0,0 +1,13 @@
const assets = require('../common/assets');
const locales = require('../common/locales');
const routes = require('./routes');
const pages = require('./routes/pages');
module.exports = function(app, devServer) {
assets.setMiddleware(devServer.middleware);
locales.setMiddleware(devServer.middleware);
routes(app);
// webpack-dev-server routes haven't been added yet
// so wait for next tick to add 404 handler
process.nextTick(() => app.use(pages.notfound));
};

16
server/languages.js Normal file
View file

@ -0,0 +1,16 @@
const { availableLanguages } = require('../package.json');
const config = require('./config');
const fs = require('fs');
const path = require('path');
function allLangs() {
const langs = fs.readdirSync(path.join(__dirname, '..', 'public', 'locales'));
langs.unshift('en-US'); // default first, TODO change for fluent-langneg
return langs;
}
if (config.l10n_dev) {
module.exports = allLangs();
} else {
module.exports = availableLanguages;
}

98
server/layout.js Normal file
View file

@ -0,0 +1,98 @@
const html = require('choo/html');
const assets = require('../common/assets');
const locales = require('../common/locales');
module.exports = function(state, body = '') {
const firaTag = state.fira
? html`<link rel="stylesheet" type="text/css" href="https://code.cdn.mozilla.net/fonts/fira.css" />`
: '';
return html`
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta property="og:title" content="${state.title}"/>
<meta name="twitter:title" content="${state.title}"/>
<meta name="description" content="${state.description}"/>
<meta property="og:description" content="${state.description}"/>
<meta name="twitter:description" content="${state.description}"/>
<meta name="twitter:card" content="summary"/>
<meta property="og:image" content="${state.baseUrl}${assets.get(
'send-fb.jpg'
)}"/>
<meta name="twitter:image" content="${state.baseUrl}${assets.get(
'send-twitter.jpg'
)}"/>
<meta property="og:url" content="${state.baseUrl}"/>
<title>${state.title}</title>
<link rel="stylesheet" type="text/css" href="${assets.get('main.css')}" />
<link rel="icon" type="image/png" href="${assets.get(
'favicon-32x32.png'
)}" sizes="32x32" />
${firaTag}
<script defer src="/jsconfig.js"></script>
<script defer src="${assets.get('runtime.js')}"></script>
<script defer src="${assets.get('vendor.js')}"></script>
<script defer src="${locales.get(state.locale)}"></script>
<script defer src="${assets.get('app.js')}"></script>
</head>
<body>
<header class="header">
<div class="send-logo">
<a href="/">
<img src="${assets.get(
'send_logo.svg'
)}" alt="Send"/><h1 class="site-title">Send</h1>
</a>
<div class="site-subtitle">
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
<div>${state.translate('siteSubtitle')}</div>
</div>
</div>
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
'siteFeedback'
)}</a>
</header>
<div class="all">
<noscript>
<h2>Firefox Send requires JavaScript</h2>
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
<p>Please enable JavaScript and try again.</p>
</noscript>
${body}
</div>
<div class="footer">
<div class="legal-links">
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
'mozilla-logo.svg'
)}" alt="mozilla"/></a>
<a href="https://www.mozilla.org/about/legal">${state.translate(
'footerLinkLegal'
)}</a>
<a href="https://testpilot.firefox.com/about">${state.translate(
'footerLinkAbout'
)}</a>
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
<a href="/legal">${state.translate('footerLinkTerms')}</a>
<a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
'footerLinkCookies'
)}</a>
</div>
<div class="social-links">
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
'github-icon.svg'
)}" alt="github"/></a>
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
'twitter-icon.svg'
)}" alt="twitter"/></a>
</div>
</div>
</body>
</html>
`;
};

View file

@ -1,4 +1,4 @@
const conf = require('./config.js');
const conf = require('./config');
const isProduction = conf.env === 'production';

26
server/prod.js Normal file
View file

@ -0,0 +1,26 @@
const express = require('express');
const path = require('path');
const Raven = require('raven');
const config = require('./config');
const routes = require('./routes');
const pages = require('./routes/pages');
if (config.sentry_dsn) {
Raven.config(config.sentry_dsn).install();
}
const app = express();
app.use(
express.static(path.resolve(__dirname, '../dist/'), {
setHeaders: function(res) {
res.set('Cache-Control', 'public, max-age=31536000, immutable');
}
})
);
routes(app);
app.use(pages.notfound);
app.listen(1443);

30
server/routes/delete.js Normal file
View file

@ -0,0 +1,30 @@
const storage = require('../storage');
function validateID(route_id) {
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
}
module.exports = async function(req, res) {
const id = req.params.id;
if (!validateID(id)) {
res.sendStatus(404);
return;
}
const delete_token = req.body.delete_token;
if (!delete_token) {
res.sendStatus(404);
return;
}
try {
const err = await storage.delete(id, delete_token);
if (!err) {
res.sendStatus(200);
}
} catch (e) {
res.sendStatus(404);
}
};

38
server/routes/download.js Normal file
View file

@ -0,0 +1,38 @@
const storage = require('../storage');
const mozlog = require('../log');
const log = mozlog('send.download');
function validateID(route_id) {
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
}
module.exports = async function(req, res) {
const id = req.params.id;
if (!validateID(id)) {
return res.sendStatus(404);
}
try {
const meta = await storage.metadata(id);
const contentLength = await storage.length(id);
res.writeHead(200, {
'Content-Disposition': `attachment; filename=${meta.filename}`,
'Content-Type': 'application/octet-stream',
'Content-Length': contentLength,
'X-File-Metadata': JSON.stringify(meta)
});
const file_stream = storage.get(id);
file_stream.on('end', async () => {
try {
await storage.forceDelete(id);
} catch (e) {
log.info('DeleteError:', id);
}
});
file_stream.pipe(res);
} catch (e) {
res.sendStatus(404);
}
};

19
server/routes/exists.js Normal file
View file

@ -0,0 +1,19 @@
const storage = require('../storage');
function validateID(route_id) {
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
}
module.exports = async (req, res) => {
const id = req.params.id;
if (!validateID(id)) {
return res.sendStatus(404);
}
try {
await storage.exists(id);
res.sendStatus(200);
} catch (e) {
res.sendStatus(404);
}
};

80
server/routes/index.js Normal file
View file

@ -0,0 +1,80 @@
const busboy = require('connect-busboy');
const helmet = require('helmet');
const bodyParser = require('body-parser');
const requestLanguage = require('express-request-language');
const languages = require('../languages');
const storage = require('../storage');
const config = require('../config');
const pages = require('./pages');
// const lang = require('fluent-langneg')
module.exports = function(app) {
app.use(
requestLanguage({
languages
})
);
app.use(helmet());
app.use(
helmet.hsts({
maxAge: 31536000,
force: config.env === 'production'
})
);
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
connectSrc: [
"'self'",
'https://sentry.prod.mozaws.net',
'https://www.google-analytics.com'
],
imgSrc: ["'self'", 'https://www.google-analytics.com'],
scriptSrc: ["'self'"],
styleSrc: ["'self'", 'https://code.cdn.mozilla.net'],
fontSrc: ["'self'", 'https://code.cdn.mozilla.net'],
formAction: ["'none'"],
frameAncestors: ["'none'"],
objectSrc: ["'none'"],
reportUri: '/__cspreport__'
}
})
);
app.use(
busboy({
limits: {
fileSize: config.max_file_size
}
})
);
app.use(bodyParser.json());
app.get('/', pages.index);
app.get('/legal', pages.legal);
app.get('/jsconfig.js', require('./jsconfig'));
app.get('/share/:id', pages.blank);
app.get('/download/:id', pages.download);
app.get('/completed', pages.blank);
app.get('/unsupported/:reason', pages.unsupported);
app.post('/api/upload', require('./upload'));
app.get('/api/download/:id', require('./download'));
app.get('/api/exists/:id', require('./exists'));
app.post('/api/delete/:id', require('./delete'));
app.get('/__version__', function(req, res) {
res.sendFile(require.resolve('../../dist/version.json'));
});
app.get('/__lbheartbeat__', function(req, res) {
res.sendStatus(200);
});
app.get('__heartbeat__', async (req, res) => {
try {
await storage.ping();
res.sendStatus(200);
} catch (e) {
res.sendStatus(500);
}
});
};

46
server/routes/jsconfig.js Normal file
View file

@ -0,0 +1,46 @@
const config = require('../config');
let sentry = '';
if (config.sentry_id) {
//eslint-disable-next-line node/no-missing-require
const version = require('../../dist/version.json');
sentry = `
var RAVEN_CONFIG = {
release: '${version.version}',
tags: {
commit: '${version.commit}'
},
dataCallback: function (data) {
var hash = window.location.hash;
if (hash) {
return JSON.parse(JSON.stringify(data).replace(new RegExp(hash.slice(1), 'g'), ''));
}
return data;
}
}
var SENTRY_ID = '${config.sentry_id}';
`;
}
let ga = '';
if (config.analytics_id) {
ga = `var GOOGLE_ANALYTICS_ID = ${config.analytics_id};`;
}
/* eslint-disable no-useless-escape */
const jsconfig = `
var isIE = /trident\\\/7\.|msie/i.test(navigator.userAgent);
var isUnsupportedPage = /\\\/unsupported/.test(location.pathname);
if (isIE && !isUnsupportedPage) {
window.location.replace('/unsupported/ie');
}
var MAXFILESIZE = ${config.max_file_size};
var EXPIRE_SECONDS = ${config.expire_seconds};
${ga}
${sentry}
`;
module.exports = function(req, res) {
res.set('Content-Type', 'application/javascript');
res.send(jsconfig);
};

68
server/routes/pages.js Normal file
View file

@ -0,0 +1,68 @@
const routes = require('../../app/routes');
const storage = require('../storage');
const state = require('../state');
function validateID(route_id) {
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
}
function stripEvents(str) {
// For CSP we need to remove all the event handler placeholders.
// It's ok, app.js will add them when it attaches to the DOM.
return str.replace(/\son\w+=""/g, '');
}
module.exports = {
index: function(req, res) {
res.send(stripEvents(routes.toString('/', state(req))));
},
blank: function(req, res) {
res.send(stripEvents(routes.toString('/blank', state(req))));
},
download: async function(req, res, next) {
const id = req.params.id;
if (!validateID(id)) {
return next();
}
try {
const efilename = await storage.filename(id);
const name = decodeURIComponent(efilename);
const size = await storage.length(id);
const ttl = await storage.ttl(id);
res.send(
stripEvents(
routes.toString(
`/download/${req.params.id}`,
Object.assign(state(req), {
fileInfo: { name, size, ttl }
})
)
)
);
} catch (e) {
next();
}
},
unsupported: function(req, res) {
res.send(
stripEvents(
routes.toString(
`/unsupported/${req.params.reason}`,
Object.assign(state(req), { fira: true })
)
)
);
},
legal: function(req, res) {
res.send(stripEvents(routes.toString('/legal', state(req))));
},
notfound: function(req, res) {
res.status(404).send(stripEvents(routes.toString('/404', state(req))));
}
};

65
server/routes/upload.js Normal file
View file

@ -0,0 +1,65 @@
const crypto = require('crypto');
const storage = require('../storage');
const config = require('../config');
const mozlog = require('../log');
const log = mozlog('send.upload');
const validateIV = route_id => {
return route_id.match(/^[0-9a-fA-F]{24}$/) !== null;
};
module.exports = function(req, res) {
const newId = crypto.randomBytes(5).toString('hex');
let meta;
try {
meta = JSON.parse(req.header('X-File-Metadata'));
} catch (e) {
res.sendStatus(400);
return;
}
if (
!meta.hasOwnProperty('id') ||
!meta.hasOwnProperty('filename') ||
!validateIV(meta.id)
) {
res.sendStatus(404);
return;
}
meta.delete = crypto.randomBytes(10).toString('hex');
req.pipe(req.busboy);
req.busboy.on(
'file',
async (fieldname, file, filename, encoding, mimeType) => {
try {
meta.mimeType = mimeType || 'application/octet-stream';
await storage.set(newId, file, filename, meta);
const protocol = config.env === 'production' ? 'https' : req.protocol;
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
res.json({
url,
delete: meta.delete,
id: newId
});
} catch (e) {
log.error('upload', e);
if (e.message === 'limit') {
return res.sendStatus(413);
}
res.sendStatus(500);
}
}
);
req.on('close', async err => {
try {
await storage.forceDelete(newId);
} catch (e) {
log.info('DeleteError:', newId);
}
});
};

View file

@ -1,328 +0,0 @@
const express = require('express');
const exphbs = require('express-handlebars');
const busboy = require('connect-busboy');
const path = require('path');
const bodyParser = require('body-parser');
const helmet = require('helmet');
const conf = require('./config.js');
const storage = require('./storage.js');
const Raven = require('raven');
const crypto = require('crypto');
const fs = require('fs');
const version = require('../dist/public/version.json');
if (conf.sentry_dsn) {
Raven.config(conf.sentry_dsn).install();
}
const mozlog = require('./log.js');
const log = mozlog('send.server');
const STATIC_PATH = path.join(__dirname, '../dist/public');
const app = express();
function allLangs() {
return fs
.readdirSync(path.join(STATIC_PATH, 'locales'))
.map(function(f) {
return f.split('.')[0];
})
.join(',');
}
function prodLangs() {
return require('../package.json').availableLanguages.join(',');
}
const availableLanguages = conf.l10n_dev ? allLangs() : prodLangs();
// dev middleware is broken at the moment because of how webpack builds the
// handlebars templates. Leaving the commented code here as a mark of shame.
// if (conf.env === 'development') {
// const webpack = require('webpack');
// const webpackDevMiddleware = require('webpack-dev-middleware');
// const config = require('../webpack.config.js');
// config.devtool = 'inline-source-map';
// const compiler = webpack(config);
// const wdm = webpackDevMiddleware(compiler, {
// publicPath: config.output.publicPath
// });
// app.use(wdm);
// }
app.set('views', 'dist/views/');
app.engine(
'handlebars',
exphbs({
defaultLayout: 'main',
layoutsDir: 'dist/views/layouts',
helpers: {
availableLanguages,
baseUrl: conf.base_url,
title: 'Firefox Send',
description:
'Encrypt and send files with a link that automatically expires to ensure your important documents dont stay online forever.'
}
})
);
app.set('view engine', 'handlebars');
app.use(helmet());
app.use(
helmet.hsts({
maxAge: 31536000,
force: conf.env === 'production'
})
);
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
connectSrc: [
"'self'",
'https://sentry.prod.mozaws.net',
'https://www.google-analytics.com'
],
imgSrc: ["'self'", 'https://www.google-analytics.com'],
scriptSrc: ["'self'"],
styleSrc: ["'self'", 'https://code.cdn.mozilla.net'],
fontSrc: ["'self'", 'https://code.cdn.mozilla.net'],
formAction: ["'none'"],
frameAncestors: ["'none'"],
objectSrc: ["'none'"],
reportUri: '/__cspreport__'
}
})
);
app.use(
busboy({
limits: {
fileSize: conf.max_file_size
}
})
);
app.use(bodyParser.json());
app.use(
'/resources',
express.static(path.join(STATIC_PATH, 'resources'), {
setHeaders: function(res) {
res.set('Cache-Control', 'public, max-age=31536000, immutable');
}
})
);
app.use(express.static(STATIC_PATH));
app.get('/', (req, res) => {
res.render('index');
});
app.get('/unsupported/:reason', (req, res) => {
const outdated = req.params.reason === 'outdated';
res.render('unsupported', {
outdated,
fira: true
});
});
app.get('/legal', (req, res) => {
res.render('legal');
});
app.get('/jsconfig.js', (req, res) => {
res.set('Content-Type', 'application/javascript');
res.render('jsconfig', {
googleAnalyticsId: conf.analytics_id,
sentryId: conf.sentry_id,
version: version.version,
commit: version.commit,
maxFileSize: conf.max_file_size,
expireSeconds: conf.expire_seconds,
layout: false
});
});
app.get('/exists/:id', async (req, res) => {
const id = req.params.id;
if (!validateID(id)) {
res.sendStatus(404);
return;
}
try {
await storage.exists(id);
res.sendStatus(200);
} catch (e) {
res.sendStatus(404);
}
});
app.get('/download/:id', async (req, res) => {
const id = req.params.id;
if (!validateID(id)) {
res.status(404).render('notfound');
return;
}
try {
const efilename = await storage.filename(id);
const filename = decodeURIComponent(efilename);
const filenameJson = JSON.stringify({ filename });
const sizeInBytes = await storage.length(id);
const ttl = await storage.ttl(id);
res.render('download', {
filename,
filenameJson,
sizeInBytes,
ttl
});
} catch (e) {
res.status(404).render('notfound');
}
});
app.get('/assets/download/:id', async (req, res) => {
const id = req.params.id;
if (!validateID(id)) {
res.sendStatus(404);
return;
}
try {
const meta = await storage.metadata(id);
const contentLength = await storage.length(id);
res.writeHead(200, {
'Content-Disposition': `attachment; filename=${meta.filename}`,
'Content-Type': 'application/octet-stream',
'Content-Length': contentLength,
'X-File-Metadata': JSON.stringify(meta)
});
const file_stream = storage.get(id);
file_stream.on('end', async () => {
try {
await storage.forceDelete(id);
} catch (e) {
log.info('DeleteError:', id);
}
});
file_stream.pipe(res);
} catch (e) {
res.sendStatus(404);
}
});
app.post('/delete/:id', async (req, res) => {
const id = req.params.id;
if (!validateID(id)) {
res.sendStatus(404);
return;
}
const delete_token = req.body.delete_token;
if (!delete_token) {
res.sendStatus(404);
return;
}
try {
const err = await storage.delete(id, delete_token);
if (!err) {
res.sendStatus(200);
}
} catch (e) {
res.sendStatus(404);
}
});
app.post('/upload', (req, res, next) => {
const newId = crypto.randomBytes(5).toString('hex');
let meta;
try {
meta = JSON.parse(req.header('X-File-Metadata'));
} catch (e) {
res.sendStatus(400);
return;
}
if (
!meta.hasOwnProperty('id') ||
!meta.hasOwnProperty('filename') ||
!validateIV(meta.id)
) {
res.sendStatus(404);
return;
}
meta.delete = crypto.randomBytes(10).toString('hex');
req.pipe(req.busboy);
req.busboy.on(
'file',
async (fieldname, file, filename, encoding, mimeType) => {
try {
meta.mimeType = mimeType || 'application/octet-stream';
await storage.set(newId, file, filename, meta);
const protocol = conf.env === 'production' ? 'https' : req.protocol;
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
res.json({
url,
delete: meta.delete,
id: newId
});
} catch (e) {
if (e.message === 'limit') {
return res.sendStatus(413);
}
res.sendStatus(500);
}
}
);
req.on('close', async err => {
try {
await storage.forceDelete(newId);
} catch (e) {
log.info('DeleteError:', newId);
}
});
});
app.get('/__lbheartbeat__', (req, res) => {
res.sendStatus(200);
});
app.get('/__heartbeat__', async (req, res) => {
try {
await storage.ping();
res.sendStatus(200);
} catch (e) {
res.sendStatus(500);
}
});
app.get('/__version__', (req, res) => {
res.sendFile(path.join(STATIC_PATH, 'version.json'));
});
const server = app.listen(conf.listen_port, () => {
log.info('startServer:', `Send app listening on port ${conf.listen_port}!`);
});
const validateID = route_id => {
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
};
const validateIV = route_id => {
return route_id.match(/^[0-9a-fA-F]{24}$/) !== null;
};
module.exports = {
server: server,
storage: storage
};

20
server/state.js Normal file
View file

@ -0,0 +1,20 @@
const config = require('./config');
const layout = require('./layout');
const locales = require('../common/locales');
module.exports = function(req) {
const locale = req.language || 'en-US';
return {
locale,
translate: locales.getTranslator(locale),
title: 'Firefox Send',
description:
'Encrypt and send files with a link that automatically expires to ensure your important documents dont stay online forever.',
baseUrl: config.base_url,
ui: {},
storage: {
files: []
},
layout
};
};

View file

@ -1,17 +1,18 @@
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const conf = require('./config.js');
const config = require('./config');
const { tmpdir } = require('os');
const fs = require('fs');
const path = require('path');
const mozlog = require('./log.js');
const mozlog = require('./log');
const log = mozlog('send.storage');
const redis = require('redis');
const redis_client = redis.createClient({
host: conf.redis_host,
host: config.redis_host,
connect_timeout: 10000
});
@ -19,7 +20,9 @@ redis_client.on('error', err => {
log.error('Redis:', err);
});
if (conf.s3_bucket) {
let tempDir = null;
if (config.s3_bucket) {
module.exports = {
filename: filename,
exists: exists,
@ -36,6 +39,8 @@ if (conf.s3_bucket) {
metadata
};
} else {
tempDir = fs.mkdtempSync(`${tmpdir()}${path.sep}send-`);
log.info('tempDir', tempDir);
module.exports = {
filename: filename,
exists: exists,
@ -113,7 +118,7 @@ function setField(id, key, value) {
function localLength(id) {
return new Promise((resolve, reject) => {
try {
resolve(fs.statSync(path.join(__dirname, '../static', id)).size);
resolve(fs.statSync(path.join(tempDir, id)).size);
} catch (err) {
reject();
}
@ -121,12 +126,12 @@ function localLength(id) {
}
function localGet(id) {
return fs.createReadStream(path.join(__dirname, '../static', id));
return fs.createReadStream(path.join(tempDir, id));
}
function localSet(newId, file, filename, meta) {
return new Promise((resolve, reject) => {
const filepath = path.join(__dirname, '../static', newId);
const filepath = path.join(tempDir, newId);
const fstream = fs.createWriteStream(filepath);
file.pipe(fstream);
file.on('limit', () => {
@ -135,7 +140,7 @@ function localSet(newId, file, filename, meta) {
});
fstream.on('finish', () => {
redis_client.hmset(newId, meta);
redis_client.expire(newId, conf.expire_seconds);
redis_client.expire(newId, config.expire_seconds);
log.info('localSet:', 'Upload Finished of ' + newId);
resolve(meta.delete);
});
@ -156,7 +161,7 @@ function localDelete(id, delete_token) {
} else {
redis_client.del(id);
log.info('Deleted:', id);
resolve(fs.unlinkSync(path.join(__dirname, '../static', id)));
resolve(fs.unlinkSync(path.join(tempDir, id)));
}
});
});
@ -165,7 +170,7 @@ function localDelete(id, delete_token) {
function localForceDelete(id) {
return new Promise((resolve, reject) => {
redis_client.del(id);
resolve(fs.unlinkSync(path.join(__dirname, '../static', id)));
resolve(fs.unlinkSync(path.join(tempDir, id)));
});
}
@ -179,7 +184,7 @@ function localPing() {
function awsLength(id) {
const params = {
Bucket: conf.s3_bucket,
Bucket: config.s3_bucket,
Key: id
};
return new Promise((resolve, reject) => {
@ -195,7 +200,7 @@ function awsLength(id) {
function awsGet(id) {
const params = {
Bucket: conf.s3_bucket,
Bucket: config.s3_bucket,
Key: id
};
@ -208,7 +213,7 @@ function awsGet(id) {
function awsSet(newId, file, filename, meta) {
const params = {
Bucket: conf.s3_bucket,
Bucket: config.s3_bucket,
Key: newId,
Body: file
};
@ -221,7 +226,7 @@ function awsSet(newId, file, filename, meta) {
return upload.promise().then(
() => {
redis_client.hmset(newId, meta);
redis_client.expire(newId, conf.expire_seconds);
redis_client.expire(newId, config.expire_seconds);
},
err => {
if (hitLimit) {
@ -240,7 +245,7 @@ function awsDelete(id, delete_token) {
reject();
} else {
const params = {
Bucket: conf.s3_bucket,
Bucket: config.s3_bucket,
Key: id
};
@ -256,7 +261,7 @@ function awsDelete(id, delete_token) {
function awsForceDelete(id) {
return new Promise((resolve, reject) => {
const params = {
Bucket: conf.s3_bucket,
Bucket: config.s3_bucket,
Key: id
};
@ -269,6 +274,6 @@ function awsForceDelete(id) {
function awsPing() {
return localPing().then(() =>
s3.headBucket({ Bucket: conf.s3_bucket }).promise()
s3.headBucket({ Bucket: config.s3_bucket }).promise()
);
}