Skip to content
Snippets Groups Projects
Commit 32ccfcd9 authored by Jason Salyers's avatar Jason Salyers
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request !263
parents 993579eb 6cadbacd
No related branches found
No related tags found
1 merge request!263Develop
...@@ -6,11 +6,11 @@ import React from 'react'; ...@@ -6,11 +6,11 @@ import React from 'react';
*/ */
const regex = { const regex = {
// eslint-disable-next-line no-useless-escape // eslint-disable-next-line no-useless-escape
sanitize: /^https:\/\/3speak\.(?:online|co|tv)\/embed\?v=([A-Za-z0-9_\-\/]+)(&.*)?$/, sanitize: /^https:\/\/3speak\.(?:online|co|tv)\/embed\?v=([A-Za-z0-9_\-\/.]+)(&.*)?$/,
// eslint-disable-next-line no-useless-escape // eslint-disable-next-line no-useless-escape
main: /(?:https?:\/\/(?:(?:3speak\.(?:online|co|tv)\/watch\?v=)|(?:3speak\.(?:online|co|tv)\/embed\?v=)))([A-Za-z0-9_\-\/]+)(&.*)?/i, main: /(?:https?:\/\/(?:(?:3speak\.(?:online|co|tv)\/watch\?v=)|(?:3speak\.(?:online|co|tv)\/embed\?v=)))([A-Za-z0-9_\-\/.]+)(&.*)?/i,
// eslint-disable-next-line no-useless-escape // eslint-disable-next-line no-useless-escape
htmlReplacement: /<a href="(https?:\/\/3speak\.(?:online|co|tv)\/watch\?v=([A-Za-z0-9_\-\/]+))".*<img.*?><\/a>/i, htmlReplacement: /<a href="(https?:\/\/3speak\.(?:online|co|tv)\/watch\?v=([A-Za-z0-9_\-\/.]+))".*<img.*?><\/a>/i,
embedShorthand: /~~~ embed:(.*?)\/(.*?) threespeak ~~~/, embedShorthand: /~~~ embed:(.*?)\/(.*?) threespeak ~~~/,
}; };
export default regex; export default regex;
......
...@@ -4,34 +4,33 @@ import { callBridge } from './steemApi'; ...@@ -4,34 +4,33 @@ import { callBridge } from './steemApi';
export async function fetchCrossPosts(posts, observer) { export async function fetchCrossPosts(posts, observer) {
const crossPostRegex = /^This is a cross post of \[@(.*?)\/(.*?)\]\(\/.*?@.*?\/.*?\) by @.*?\.<br>/; const crossPostRegex = /^This is a cross post of \[@(.*?)\/(.*?)\]\(\/.*?@.*?\/.*?\) by @.*?\.<br>/;
const crossPostPromises = []; const crossPostPromises = [];
const crossPosts = {};
const content = {}; const content = {};
const keys = []; const keys = [];
for (let idx = 0; idx < posts.length; idx += 1) { if (Array.isArray(posts)) {
const post = posts[idx]; for (let idx = 0; idx < posts.length; idx += 1) {
if (!post || !post.body) const post = posts[idx];
continue; if (!post || !post.body) continue;
const crossPostMatches = crossPostRegex.exec(post.body); const crossPostMatches = crossPostRegex.exec(post.body);
if (crossPostMatches) {
const [, crossPostAuthor, crossPostPermlink] = crossPostMatches;
const crossPostParams = {
author: crossPostAuthor,
permlink: crossPostPermlink,
observer,
};
crossPostPromises.push(callBridge('get_post', crossPostParams));
post.cross_post_key = `${crossPostAuthor}/${crossPostPermlink}`;
}
if (crossPostMatches) { const key = post.author + '/' + post.permlink;
const [, crossPostAuthor, crossPostPermlink] = crossPostMatches; content[key] = post;
const crossPostParams = { keys.push(key);
author: crossPostAuthor,
permlink: crossPostPermlink,
observer,
};
crossPostPromises.push(callBridge('get_post', crossPostParams));
post.cross_post_key = `${crossPostAuthor}/${crossPostPermlink}`;
} }
const key = post.author + '/' + post.permlink;
content[key] = post;
keys.push(key);
} }
const crossPosts = {};
if (crossPostPromises.length > 0) { if (crossPostPromises.length > 0) {
try { try {
const responses = await settlePromises(crossPostPromises); const responses = await settlePromises(crossPostPromises);
...@@ -41,9 +40,7 @@ export async function fetchCrossPosts(posts, observer) { ...@@ -41,9 +40,7 @@ export async function fetchCrossPosts(posts, observer) {
if (response.state === 'resolved') { if (response.state === 'resolved') {
const crossPost = response.value; const crossPost = response.value;
const crossPostKey = `${crossPost.author}/${ const crossPostKey = `${crossPost.author}/${crossPost.permlink}`;
crossPost.permlink
}`;
crossPosts[crossPostKey] = crossPost; crossPosts[crossPostKey] = crossPost;
} else { } else {
console.error('cross post error', response); console.error('cross post error', response);
......
...@@ -39,6 +39,7 @@ export default ({ large = true, highQualityPost = true, noImage = false, sanitiz ...@@ -39,6 +39,7 @@ export default ({ large = true, highQualityPost = true, noImage = false, sanitiz
// style is subject to attack, filtering more below // style is subject to attack, filtering more below
td: ['style'], td: ['style'],
th: ['style'],
img: ['src', 'srcset', 'alt', 'class'], img: ['src', 'srcset', 'alt', 'class'],
// title is only set in the case of an external link warning // title is only set in the case of an external link warning
...@@ -127,9 +128,25 @@ export default ({ large = true, highQualityPost = true, noImage = false, sanitiz ...@@ -127,9 +128,25 @@ export default ({ large = true, highQualityPost = true, noImage = false, sanitiz
attribs: attys, attribs: attys,
}; };
}, },
th: (tagName, attribs) => {
const attys = {};
const allowedStyles = ['text-align:right', 'text-align:left', 'text-align:center'];
if (allowedStyles.indexOf(attribs.style) !== -1) {
attys.style = attribs.style;
}
return {
tagName,
attribs: attys,
};
},
td: (tagName, attribs) => { td: (tagName, attribs) => {
const attys = {}; const attys = {};
if (attribs.style === 'text-align:right') attys.style = 'text-align:right'; const allowedStyles = ['text-align:right', 'text-align:left', 'text-align:center'];
if (allowedStyles.indexOf(attribs.style) !== -1) {
attys.style = attribs.style;
}
return { return {
tagName, tagName,
attribs: attys, attribs: attys,
......
...@@ -133,9 +133,9 @@ export async function getStateAsync(url, observer, ssr = false) { ...@@ -133,9 +133,9 @@ export async function getStateAsync(url, observer, ssr = false) {
if (ssr && account) { if (ssr && account) {
// TODO: move to global reducer? // TODO: move to global reducer?
const profile = await callBridge('get_profile', { account }); const profile = await callBridge('get_profile', { account });
const hive_power = await getHivePowerForUser(account);
if (profile && profile['name']) { if (profile && profile['name']) {
const hive_power = await getHivePowerForUser(account);
state['profiles'][account] = { state['profiles'][account] = {
...profile, ...profile,
stats: { stats: {
......
...@@ -40,42 +40,16 @@ const env = process.env.NODE_ENV || 'development'; ...@@ -40,42 +40,16 @@ const env = process.env.NODE_ENV || 'development';
const cacheOpts = { maxAge: 86400000, gzip: true, buffer: true }; const cacheOpts = { maxAge: 86400000, gzip: true, buffer: true };
// import ads.txt to be served statically // import ads.txt to be served statically
const adstxt = fs.readFileSync( const adstxt = fs.readFileSync(path.join(__dirname, '../app/assets/ads.txt'), 'utf8');
path.join(__dirname, '../app/assets/ads.txt'),
'utf8'
);
// Serve static assets without fanfare // Serve static assets without fanfare
app.use( app.use(favicon(path.join(__dirname, '../app/assets/images/favicons/favicon.ico')));
favicon(path.join(__dirname, '../app/assets/images/favicons/favicon.ico'))
);
app.use( app.use(mount('/favicons', staticCache(path.join(__dirname, '../app/assets/images/favicons'), cacheOpts)));
mount(
'/favicons',
staticCache(
path.join(__dirname, '../app/assets/images/favicons'),
cacheOpts
)
)
);
app.use( app.use(mount('/images', staticCache(path.join(__dirname, '../app/assets/images'), cacheOpts)));
mount(
'/images',
staticCache(path.join(__dirname, '../app/assets/images'), cacheOpts)
)
);
app.use( app.use(mount('/javascripts', staticCache(path.join(__dirname, '../app/assets/javascripts'), cacheOpts)));
mount(
'/javascripts',
staticCache(
path.join(__dirname, '../app/assets/javascripts'),
cacheOpts
)
)
);
app.use( app.use(
mount('/ads.txt', function*() { mount('/ads.txt', function*() {
...@@ -86,9 +60,7 @@ app.use( ...@@ -86,9 +60,7 @@ app.use(
// Proxy asset folder to webpack development server in development mode // Proxy asset folder to webpack development server in development mode
if (env === 'development') { if (env === 'development') {
const webpack_dev_port = process.env.PORT const webpack_dev_port = process.env.PORT ? parseInt(process.env.PORT) + 1 : 8081;
? parseInt(process.env.PORT) + 1
: 8081;
const proxyhost = 'http://0.0.0.0:' + webpack_dev_port; const proxyhost = 'http://0.0.0.0:' + webpack_dev_port;
console.log('proxying to webpack dev server at ' + proxyhost); console.log('proxying to webpack dev server at ' + proxyhost);
const proxy = require('koa-proxy')({ const proxy = require('koa-proxy')({
...@@ -97,23 +69,14 @@ if (env === 'development') { ...@@ -97,23 +69,14 @@ if (env === 'development') {
}); });
app.use(mount('/assets', proxy)); app.use(mount('/assets', proxy));
} else { } else {
app.use( app.use(mount('/assets', staticCache(path.join(__dirname, '../../dist'), cacheOpts)));
mount(
'/assets',
staticCache(path.join(__dirname, '../../dist'), cacheOpts)
)
);
} }
let resolvedAssets = false; let resolvedAssets = false;
let supportedLocales = false; let supportedLocales = false;
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
resolvedAssets = require(path.join( resolvedAssets = require(path.join(__dirname, '../..', '/tmp/webpack-stats-prod.json'));
__dirname,
'../..',
'/tmp/webpack-stats-prod.json'
));
supportedLocales = getSupportedLocales(); supportedLocales = getSupportedLocales();
} }
...@@ -160,9 +123,7 @@ app.use(function*(next) { ...@@ -160,9 +123,7 @@ app.use(function*(next) {
this.body = { this.body = {
status: 'ok', status: 'ok',
docker_tag: process.env.DOCKER_TAG ? process.env.DOCKER_TAG : false, docker_tag: process.env.DOCKER_TAG ? process.env.DOCKER_TAG : false,
source_commit: process.env.SOURCE_COMMIT source_commit: process.env.SOURCE_COMMIT ? process.env.SOURCE_COMMIT : false,
? process.env.SOURCE_COMMIT
: false,
}; };
return; return;
} }
...@@ -211,16 +172,30 @@ app.use(function*(next) { ...@@ -211,16 +172,30 @@ app.use(function*(next) {
} }
} }
// remember ch, cn, r url params in the session and remove them from url // this.url is a relative URL, it does not include the scheme
if (this.method === 'GET' && /\?[^\w]*(ch=|cn=|r=)/.test(this.url)) { const [pathString, queryString] = this.url.split('?');
let redir = this.url.replace(/((ch|cn|r)=[^&]+)/gi, r => { const urlParams = new URLSearchParams(queryString);
const p = r.split('=');
if (p.length === 2) this.session[p[0]] = p[1]; let paramFound = false;
return ''; if (this.url.indexOf('?') !== -1) {
const paramsToProcess = ['ch', 'cn', 'r'];
paramsToProcess.forEach(paramToProcess => {
if (urlParams.has(paramToProcess)) {
const paramValue = urlParams.get(paramToProcess);
if (paramValue) {
paramFound = true;
this.session[paramToProcess] = paramValue;
urlParams.delete(paramToProcess);
}
}
}); });
redir = redir.replace(/&&&?/, ''); }
redir = redir.replace(/\?&?$/, '');
console.log(`server redirect ${this.url} -> ${redir}`); if (paramFound) {
const newQueryString = urlParams.toString();
const redir = `${pathString.replace(/\/\//g, '/')}${newQueryString ? `?${newQueryString}` : ''}`;
this.status = 302; this.status = 302;
this.redirect(redir); this.redirect(redir);
} else { } else {
...@@ -248,12 +223,7 @@ if (env === 'production') { ...@@ -248,12 +223,7 @@ if (env === 'production') {
// }) // })
// ); // );
app.use( app.use(mount('/static', staticCache(path.join(__dirname, '../app/assets/static'), cacheOpts)));
mount(
'/static',
staticCache(path.join(__dirname, '../app/assets/static'), cacheOpts)
)
);
app.use( app.use(
mount('/robots.txt', function*() { mount('/robots.txt', function*() {
...@@ -322,11 +292,7 @@ if (env !== 'test') { ...@@ -322,11 +292,7 @@ if (env !== 'test') {
yield appRender(this, supportedLocales, resolvedAssets); yield appRender(this, supportedLocales, resolvedAssets);
const bot = this.state.isBot; const bot = this.state.isBot;
if (bot) { if (bot) {
console.log( console.log(` --> ${this.method} ${this.originalUrl} ${this.status} (BOT '${bot}')`);
` --> ${this.method} ${this.originalUrl} ${
this.status
} (BOT '${bot}')`
);
} }
}); });
...@@ -341,10 +307,7 @@ if (env !== 'test') { ...@@ -341,10 +307,7 @@ if (env !== 'test') {
} }
// if a worker dies replace it so application keeps running // if a worker dies replace it so application keeps running
cluster.on('exit', function(worker) { cluster.on('exit', function(worker) {
console.log( console.log('error: worker %d died, starting a new one', worker.id);
'error: worker %d died, starting a new one',
worker.id
);
cluster.fork(); cluster.fork();
}); });
} else { } else {
...@@ -362,7 +325,6 @@ if (env !== 'test') { ...@@ -362,7 +325,6 @@ if (env !== 'test') {
// set PERFORMANCE_TRACING to the number of seconds desired for // set PERFORMANCE_TRACING to the number of seconds desired for
// logging hardware stats to the console // logging hardware stats to the console
if (process.env.PERFORMANCE_TRACING) if (process.env.PERFORMANCE_TRACING) setInterval(hardwareStats, 1000 * process.env.PERFORMANCE_TRACING);
setInterval(hardwareStats, 1000 * process.env.PERFORMANCE_TRACING);
module.exports = app; module.exports = app;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment