diff --git a/app/components/App.scss b/app/components/App.scss index 1a67ef86..43273120 100644 --- a/app/components/App.scss +++ b/app/components/App.scss @@ -142,6 +142,9 @@ HTML { filter: none; -webkit-filter: none; } +.blurring { + filter: blur(5px); +} .App__announcement { .logo-icon { @@ -195,3 +198,7 @@ HTML { display: none; } } + +.reveal-blurring { + backdrop-filter: blur(3px); +} diff --git a/app/components/cards/PostFull.jsx b/app/components/cards/PostFull.jsx index d465d0be..c79968b0 100644 --- a/app/components/cards/PostFull.jsx +++ b/app/components/cards/PostFull.jsx @@ -10,7 +10,7 @@ import transaction from 'app/redux/Transaction'; import { repLog10, parsePayoutAmount } from 'app/utils/ParsersAndFormatters'; import extractContent from 'app/utils/ExtractContent'; import { immutableAccessor, objAccessor } from 'app/utils/Accessors'; -import { isPostVisited, visitPost } from 'app/utils/helpers'; +import { isPostVisited, visitPost, randomString } from 'app/utils/helpers'; import Icon from 'app/components/elements/Icon'; import TimeVersions from 'app/components/elements/TimeVersions'; import Voting from 'app/components/elements/Voting'; @@ -129,7 +129,7 @@ class PostFull extends React.Component { } shouldComponentUpdate(props, state) { - const { cont, post, prevPosts, username, pso } = this.props; + const { cont, post, prevPosts, username, pso, loginBlurring } = this.props; return ( cont !== props.cont || @@ -137,7 +137,8 @@ class PostFull extends React.Component { prevPosts.length !== props.prevPosts.length || username !== props.username || pso !== props.pso || - this.state !== state + this.state !== state || + props.loginBlurring !== loginBlurring ); } @@ -202,7 +203,7 @@ class PostFull extends React.Component { }; render() { - const { username, post, cont } = this.props; + const { username, post, cont, loginBlurring } = this.props; const { showReply, showEdit } = this.state; const postContent = cont.get(post); @@ -223,7 +224,7 @@ class PostFull extends React.Component { link = `/${category}${link}`; } - if (process.env.BROWSER && title) { + if (process.env.BROWSER && !loginBlurring && title) { document.title = title + ' | ' + SEO_TITLE; } @@ -283,7 +284,7 @@ class PostFull extends React.Component { return (
@@ -362,7 +363,7 @@ class PostFull extends React.Component { } _renderContent(postContent, content, jsonMetadata, authorRepLog10) { - const { username, post, pso } = this.props; + const { username, post, pso, loginBlurring } = this.props; const { author, permlink, category } = content; const url = `/${category}/@${author}/${permlink}`; @@ -399,15 +400,16 @@ class PostFull extends React.Component { ); } + const rt = loginBlurring ? randomString(content.root_title) : content.root_title postHeader = (

- {tt('g.re')}: {content.root_title} + {tt('g.re')}: {rt}

{tt('g.you_are_viewing_a_single_comments_thread_from')}:
-

{content.root_title}

+

{rt}

); } else { + const ct = loginBlurring ? randomString(content.title) : content.title postHeader = (

- {content.title} + {ct}

); } + contentBody = loginBlurring ? randomString(contentBody) : contentBody + const main = [
@@ -592,11 +597,15 @@ export default connect( const pso = state.global.get('pso') + const loginDefault = state.user.get('loginDefault') + const loginBlurring = loginDefault && loginDefault.get('blurring') + return { ...props, username, prevPosts, - pso: pso ? pso.toJS() : null + pso: pso ? pso.toJS() : null, + loginBlurring } }, diff --git a/app/components/cards/PostSummary.jsx b/app/components/cards/PostSummary.jsx index 197485d9..9d87631a 100644 --- a/app/components/cards/PostSummary.jsx +++ b/app/components/cards/PostSummary.jsx @@ -29,6 +29,7 @@ import { authRegisterUrl, } from 'app/utils/AuthApiClient' import { hideSummary } from 'app/utils/ContentAccess' import extractContent from 'app/utils/ExtractContent' import {authorNameAndRep} from 'app/utils/ComponentFormatters' +import { randomString } from 'app/utils/helpers' import { addHighlight, unsubscribePost } from 'app/utils/NotifyApiClient' import { detransliterate } from 'app/utils/ParsersAndFormatters' import { proxifyImageUrl } from 'app/utils/ProxifyUrl' @@ -86,7 +87,8 @@ class PostSummary extends React.Component { state.revealNsfw !== this.state.revealNsfw || props.visited !== this.props.visited || props.gray !== this.props.gray || - props.encrypted !== this.props.encrypted + props.encrypted !== this.props.encrypted || + props.loginBlurring !== this.props.loginBlurring } componentDidUpdate(prevProps) { @@ -150,7 +152,7 @@ class PostSummary extends React.Component { const {currentCategory, thumbSize, onClick} = this.props; const {post, content, pending_payout, total_payout, cashout_time, blockEye} = this.props; const {account} = this.props; - const {nsfwPref, username} = this.props + const {nsfwPref, username, loginBlurring} = this.props if (!content) return null; let reblogged_by; @@ -225,6 +227,11 @@ class PostSummary extends React.Component { comments_link = p.link + '#comments'; } + if (loginBlurring) { + title_text = randomString(title_text) + desc = randomString(desc) + } + if (title_link_url.includes('fm-') && $STM_Config.forums) { let parts = title_link_url.split('/'); for (let [_id, forum] of Object.entries($STM_Config.forums)) { @@ -362,6 +369,7 @@ class PostSummary extends React.Component { } const commentClasses = [] if(gray) commentClasses.push('downvoted') // rephide + if (loginBlurring) commentClasses.push('blurring') total_search = total_search ? {tt('g.and_more_search_posts_COUNT', { COUNT: total_search })} @@ -442,9 +450,12 @@ export default connect( const stats = content.get('stats', Map()).toJS() gray = stats.gray } + const loginDefault = state.user.get('loginDefault') + const loginBlurring = loginDefault && loginDefault.get('blurring') return { post, content, gray, pending_payout, total_payout, event_count, encrypted, - username: state.user.getIn(['current', 'username']) || state.offchain.get('account') + username: state.user.getIn(['current', 'username']) || state.offchain.get('account'), + loginBlurring }; }, diff --git a/app/components/modules/Modals.jsx b/app/components/modules/Modals.jsx index 547d18a4..d51bb37a 100644 --- a/app/components/modules/Modals.jsx +++ b/app/components/modules/Modals.jsx @@ -47,7 +47,7 @@ class Modals extends React.Component { this.shouldComponentUpdate = shouldComponentUpdate(this, 'Modals'); } - onLoginBackdropClick = (e) => { + onLoginTryClose = (e) => { const { loginUnclosable } = this.props; if (loginUnclosable) throw new Error('Closing login modal is forbidden here'); @@ -56,6 +56,7 @@ class Modals extends React.Component { render() { const { show_login_modal, + loginBlurring, show_confirm_modal, show_donate_modal, show_gift_nft_modal, @@ -84,9 +85,11 @@ class Modals extends React.Component { return n; }) : []; + const loginClass = loginBlurring ? 'reveal-blurring' : undefined + return (
- {show_login_modal && + {show_login_modal && } {show_confirm_modal && @@ -129,9 +132,11 @@ export default connect( state => { const loginDefault = state.user.get('loginDefault'); const loginUnclosable = loginDefault && loginDefault.get('unclosable'); + const loginBlurring = loginDefault && loginDefault.get('blurring') return { show_login_modal: state.user.get('show_login_modal'), loginUnclosable, + loginBlurring, show_confirm_modal: state.transaction.get('show_confirm_modal'), show_donate_modal: state.user.get('show_donate_modal'), show_gift_nft_modal: state.user.get('show_gift_nft_modal'), diff --git a/app/redux/User.js b/app/redux/User.js index 49c4c5c5..d39cb1f0 100644 --- a/app/redux/User.js +++ b/app/redux/User.js @@ -33,6 +33,19 @@ export default createModule({ name: 'user', initialState: defaultState, transformations: [ + { + action: 'REQUIRE_LOGIN', + reducer: (state, {payload}) => { + return state.merge({ + show_login_modal: true, + loginDefault: { + unclosable: true, + cancelIsRegister: true, + blurring: true + } + }) + } + }, { action: 'SHOW_LOGIN', reducer: (state, {payload}) => { diff --git a/app/utils/helpers.js b/app/utils/helpers.js index 4d79d5d6..ec3d88e7 100644 --- a/app/utils/helpers.js +++ b/app/utils/helpers.js @@ -1,3 +1,18 @@ +export function randomString(str) { + let res = '' + const abc = 'abcdefghijklmnopqrstuvwxz' + for (let i = 0; i < str.length; ++i) { + const c = str[i] + if (c === ' ') { + res += c + continue + } + const nc = abc[Math.floor(Math.random() * abc.length)] + res += nc + } + return res +} + export function encode(str) { let hash = 0, chr; if (str.length === 0) return hash; diff --git a/server/index.js b/server/index.js index c325c4a3..39d07941 100755 --- a/server/index.js +++ b/server/index.js @@ -52,6 +52,7 @@ global.$STM_Config = { forums: config.get('forums'), blocked_users, blocked_posts, + authorization_required: config.has('authorization_required') && config.get('authorization_required'), ui_version: version || '1.0-unknown', }; diff --git a/shared/UniversalRender.jsx b/shared/UniversalRender.jsx index ffa71cfa..2236b97a 100644 --- a/shared/UniversalRender.jsx +++ b/shared/UniversalRender.jsx @@ -11,7 +11,6 @@ import { match, applyRouterMiddleware } from 'react-router'; -import * as api from 'app/utils/APIWrapper' import { Provider } from 'react-redux'; import RootRoute from 'app/RootRoute'; import {createStore, applyMiddleware, compose} from 'redux'; @@ -19,6 +18,8 @@ import { browserHistory } from 'react-router'; import { useScroll } from 'react-router-scroll'; import createSagaMiddleware from 'redux-saga'; import { syncHistoryWithStore } from 'react-router-redux'; + +import * as api from 'app/utils/APIWrapper' import rootReducer from 'app/redux/RootReducer'; import rootSaga from 'app/redux/RootSaga'; import {component as NotFound} from 'app/components/pages/NotFound'; @@ -26,6 +27,7 @@ import extractMeta from 'app/utils/ExtractMeta'; import Translator from 'app/Translator'; import getState from 'app/utils/StateBuilder'; import {routeRegex} from "app/ResolveRoute"; +import session from 'app/utils/session' import {contentStats} from 'app/utils/StateFunctions' import {APP_NAME, SEO_TITLE} from 'app/client_config'; import constants from 'app/redux/constants'; @@ -80,6 +82,9 @@ export async function serverRender({ if (process.env.BROWSER) { const store = createStore(rootReducer, initial_state, middleware); + if (!session.load().currentName && $STM_Config.authorization_required) { + store.dispatch({type: 'user/REQUIRE_LOGIN', payload: {}}); + } // sagaMiddleware.run(PollDataSaga).done // .then(() => console.log('PollDataSaga is finished')) // .catch(err => console.log('PollDataSaga is finished with error', err)); @@ -161,6 +166,9 @@ export async function serverRender({ offchain.server_location = location; serverStore = createStore(rootReducer, { global: onchain, offchain}); + if (!offchain.account && $STM_Config.authorization_required) { + serverStore.dispatch({type: 'user/REQUIRE_LOGIN', payload: {}}); + } serverStore.dispatch({type: '@@router/LOCATION_CHANGE', payload: {pathname: location}}); // TODO: maybe use request to golosnotify to fetch counters? /*if (offchain.account) { @@ -221,6 +229,9 @@ export async function serverRender({ export function clientRender(initialState) { const store = createStore(rootReducer, initialState, middleware); + if (!session.load().currentName && $STM_Config.authorization_required) { + store.dispatch({type: 'user/REQUIRE_LOGIN', payload: {}}); + } sagaMiddleware.run(rootSaga) const history = syncHistoryWithStore(browserHistory, store);