mirror of
https://github.com/wassname/talk.git
synced 2026-07-20 12:40:47 +08:00
PAss the token around.
This commit is contained in:
@@ -7,7 +7,7 @@ const passport = require('./services/passport');
|
||||
const session = require('express-session');
|
||||
const RedisStore = require('connect-redis')(session);
|
||||
const redis = require('./services/redis');
|
||||
const csrf = require('csurf');
|
||||
const cookieParser = require('cookie-parser');
|
||||
|
||||
const app = express();
|
||||
|
||||
@@ -70,9 +70,15 @@ app.use(session(session_opts));
|
||||
// CSRF MIDDLEWARE
|
||||
//==============================================================================
|
||||
|
||||
app.use(csrf());
|
||||
// Use CSRF only if we are not testing.
|
||||
if (app.get('env') !== 'test') {
|
||||
console.log('DEBUGT NO TEST');
|
||||
app.use(cookieParser());
|
||||
}
|
||||
|
||||
app.use((err, req, res, next) => {
|
||||
console.log('DEBUG EN SERVER', req.csrfToken());
|
||||
|
||||
res.locals._csrf = req.csrfToken();
|
||||
return next();
|
||||
});
|
||||
|
||||
@@ -96,7 +96,7 @@ class CommentStream extends Component {
|
||||
const rootItem = this.props.items.assets && this.props.items.assets[rootItemId];
|
||||
const {actions, users, comments} = this.props.items;
|
||||
const {status, moderation, closedMessage, charCount, charCountEnable} = this.props.config;
|
||||
const {loggedIn, isAdmin, user, showSignInDialog, signInOffset} = this.props.auth;
|
||||
const {loggedIn, isAdmin, user, showSignInDialog, signInOffset, csrfToken} = this.props.auth;
|
||||
const {activeTab} = this.state;
|
||||
const banned = (this.props.userData.status === 'banned');
|
||||
|
||||
@@ -138,7 +138,7 @@ class CommentStream extends Component {
|
||||
</div>
|
||||
: <p>{closedMessage}</p>
|
||||
}
|
||||
{!loggedIn && <SignInContainer offset={signInOffset} />}
|
||||
{!loggedIn && <SignInContainer offset={signInOffset} csrfToken={csrfToken}/>}
|
||||
{
|
||||
rootItem.comments && rootItem.comments.map((commentId) => {
|
||||
const comment = comments[commentId];
|
||||
|
||||
@@ -24,6 +24,7 @@ const signInSuccess = (user, isAdmin) => ({type: actions.FETCH_SIGNIN_SUCCESS, u
|
||||
const signInFailure = error => ({type: actions.FETCH_SIGNIN_FAILURE, error});
|
||||
|
||||
export const fetchSignIn = (formData) => dispatch => {
|
||||
console.log('DEBUG FORMDATA', formData);
|
||||
dispatch(signInRequest());
|
||||
coralApi('/auth/local', {method: 'POST', body: formData})
|
||||
.then(({user}) => {
|
||||
@@ -120,17 +121,22 @@ export const invalidForm = error => ({type: actions.INVALID_FORM, error});
|
||||
const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST});
|
||||
const checkLoginSuccess = (user, isAdmin) => ({type: actions.CHECK_LOGIN_SUCCESS, user, isAdmin});
|
||||
const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error});
|
||||
const checkCSRFToken = (csrfToken) => ({type: actions.CHECK_CSRF_TOKEN, csrfToken});
|
||||
|
||||
export const checkLogin = () => dispatch => {
|
||||
dispatch(checkLoginRequest());
|
||||
coralApi('/auth')
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
.then((result) => {
|
||||
if (result.csrfToken !== null) {
|
||||
dispatch(checkCSRFToken(result.csrfToken));
|
||||
}
|
||||
|
||||
if (!result.user) {
|
||||
throw new Error('Not logged in');
|
||||
}
|
||||
|
||||
const isAdmin = !!user.roles.filter(i => i === 'admin').length;
|
||||
dispatch(checkLoginSuccess(user, isAdmin));
|
||||
const isAdmin = !!result.user.roles.filter(i => i === 'admin').length;
|
||||
dispatch(checkLoginSuccess(result.user, isAdmin));
|
||||
})
|
||||
.catch(error => dispatch(checkLoginFailure(error)));
|
||||
};
|
||||
|
||||
@@ -31,3 +31,4 @@ export const CHECK_LOGIN_REQUEST = 'CHECK_LOGIN_REQUEST';
|
||||
export const CHECK_LOGIN_SUCCESS = 'CHECK_LOGIN_SUCCESS';
|
||||
export const CHECK_LOGIN_FAILURE = 'CHECK_LOGIN_FAILURE';
|
||||
|
||||
export const CHECK_CSRF_TOKEN = 'CHECK_CSRF_TOKEN';
|
||||
|
||||
@@ -11,7 +11,8 @@ const initialState = Map({
|
||||
error: '',
|
||||
passwordRequestSuccess: null,
|
||||
passwordRequestFailure: null,
|
||||
successSignUp: false
|
||||
successSignUp: false,
|
||||
csrfToken: ''
|
||||
});
|
||||
|
||||
const purge = user => {
|
||||
@@ -41,6 +42,9 @@ export default function auth (state = initialState, action) {
|
||||
.set('view', action.view);
|
||||
case actions.CLEAN_STATE:
|
||||
return initialState;
|
||||
case actions.CHECK_CSRF_TOKEN:
|
||||
return state
|
||||
.set('csrfToken', action.csrfToken);
|
||||
case actions.FETCH_SIGNIN_REQUEST:
|
||||
return state
|
||||
.set('isLoading', true);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
export const FormCSRFInput = React.createClass({
|
||||
render() {
|
||||
const {csrfToken} = this.props;
|
||||
|
||||
return (
|
||||
<input type="hidden" name="_csrf" value={csrfToken} />
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
const FormCSRFField = ({...props}) => (
|
||||
<input type="hidden" name="csrfToken" value={props.csrfToken} />
|
||||
);
|
||||
|
||||
export default FormCSRFField;
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.css';
|
||||
import Button from 'coral-ui/components/Button';
|
||||
import FormCSRFField from 'coral-plugin-csrf/FormCSRFField';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../translations';
|
||||
const lang = new I18n(translations);
|
||||
@@ -17,7 +18,7 @@ class ForgotContent extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const {changeView, auth} = this.props;
|
||||
const {changeView, auth, csrfToken} = this.props;
|
||||
const {passwordRequestSuccess, passwordRequestFailure} = auth;
|
||||
|
||||
return (
|
||||
@@ -26,6 +27,9 @@ class ForgotContent extends React.Component {
|
||||
<h1>{lang.t('signIn.recoverPassword')}</h1>
|
||||
</div>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<FormCSRFField
|
||||
csrfToken={csrfToken}
|
||||
/>
|
||||
<div className={styles.formField}>
|
||||
<label htmlFor="email">{lang.t('signIn.email')}</label>
|
||||
<input
|
||||
|
||||
@@ -12,7 +12,7 @@ const SignDialog = ({open, view, handleClose, offset, ...props}) => (
|
||||
open={open}
|
||||
style={{
|
||||
position: 'relative',
|
||||
top: offset !== 0 && offset
|
||||
top: offset !== 0 && offset
|
||||
}}>
|
||||
<span className={styles.close} onClick={handleClose}>×</span>
|
||||
{view === 'SIGNIN' && <SignInContent {...props} />}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import Button from 'coral-ui/components/Button';
|
||||
import FormField from './FormField';
|
||||
import FormCSRFField from 'coral-plugin-csrf/FormCSRFField';
|
||||
import Alert from './Alert';
|
||||
import Spinner from 'coral-ui/components/Spinner';
|
||||
import styles from './styles.css';
|
||||
@@ -27,6 +28,9 @@ const SignInContent = ({handleChange, formData, ...props}) => (
|
||||
</div>
|
||||
{ props.auth.error && <Alert>{props.auth.error}</Alert> }
|
||||
<form onSubmit={props.handleSignIn}>
|
||||
<FormCSRFField
|
||||
csrfToken={props.csrfToken}
|
||||
/>
|
||||
<FormField
|
||||
id="email"
|
||||
type="email"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import FormField from './FormField';
|
||||
import FormCSRFField from 'coral-plugin-csrf/FormCSRFField';
|
||||
import Alert from './Alert';
|
||||
import Button from 'coral-ui/components/Button';
|
||||
import Spinner from 'coral-ui/components/Spinner';
|
||||
@@ -28,6 +29,9 @@ const SignUpContent = ({handleChange, formData, ...props}) => (
|
||||
</div>
|
||||
{ props.auth.error && <Alert>{props.auth.error}</Alert> }
|
||||
<form onSubmit={props.handleSignUp}>
|
||||
<FormCSRFField
|
||||
csrfToken={props.csrfToken}
|
||||
/>
|
||||
<FormField
|
||||
id="email"
|
||||
type="email"
|
||||
|
||||
@@ -28,7 +28,8 @@ class SignInContainer extends Component {
|
||||
email: '',
|
||||
displayName: '',
|
||||
password: '',
|
||||
confirmPassword: ''
|
||||
confirmPassword: '',
|
||||
csrfToken: ''
|
||||
},
|
||||
errors: {},
|
||||
showErrors: false
|
||||
@@ -121,6 +122,7 @@ class SignInContainer extends Component {
|
||||
|
||||
handleSignIn(e) {
|
||||
e.preventDefault();
|
||||
this.state.formData.csrfToken = this.props.csrfToken;
|
||||
this.props.fetchSignIn(this.state.formData);
|
||||
}
|
||||
|
||||
@@ -129,7 +131,7 @@ class SignInContainer extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {auth, showSignInDialog, noButton, offset} = this.props;
|
||||
const {auth, showSignInDialog, noButton, offset, csrfToken} = this.props;
|
||||
return (
|
||||
<div>
|
||||
{!noButton && <Button id='coralSignInButton' onClick={showSignInDialog} full>
|
||||
@@ -139,6 +141,7 @@ class SignInContainer extends Component {
|
||||
open={auth.showSignInDialog}
|
||||
view={auth.view}
|
||||
offset={offset}
|
||||
csrfToken={csrfToken}
|
||||
{...this}
|
||||
{...this.state}
|
||||
{...this.props}
|
||||
|
||||
@@ -15,19 +15,17 @@ const parseForm = bodyParser.urlencoded({extended: false});
|
||||
/**
|
||||
* This returns the user if they are logged in.
|
||||
*/
|
||||
router.get('/', (req, res, next) => {
|
||||
router.get('/', csrfProtection, (req, res, next) => {
|
||||
if (req.user) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// When there is no user on the request, then just send back a 204 to this
|
||||
// request. It's not really "an error" if what they asked for isn't available,
|
||||
// but it could be.
|
||||
res.status(204).end();
|
||||
// When there is no user on the request, then just send back the CSRF token.
|
||||
res.json({csrfToken: req.csrfToken()});
|
||||
}, (req, res) => {
|
||||
|
||||
// Send back the user object.
|
||||
res.json(req.user.toObject());
|
||||
res.json(req.user.toObject(), {csrfToken: req.csrfToken()});
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -57,8 +55,8 @@ const HandleAuthCallback = (req, res, next) => (err, user) => {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// We logged in the user! Let's send back the user data.
|
||||
res.json({user});
|
||||
// We logged in the user! Let's send back the user data and the CSRF token.
|
||||
res.json({user, '_csrf': req.csrfToken()});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -89,7 +87,7 @@ const HandleAuthPopupCallback = (req, res, next) => (err, user) => {
|
||||
* Local auth endpoint, will recieve a email and password
|
||||
*/
|
||||
router.post('/local', parseForm, csrfProtection, (req, res, next) => {
|
||||
|
||||
|
||||
// Perform the local authentication.
|
||||
passport.authenticate('local', HandleAuthCallback(req, res, next))(req, res, next);
|
||||
});
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ router.get('/assets/:asset_title', csrfProtection, (req, res) => {
|
||||
return res.render('article', {
|
||||
title: req.params.asset_title.split('-').join(' '),
|
||||
basePath: '/client/embed/stream',
|
||||
csrfToken: req.csrfToken()
|
||||
_csrf: req.csrfToken()
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ const app = require('../../../../app');
|
||||
const chai = require('chai');
|
||||
const expect = chai.expect;
|
||||
|
||||
const csrf = require('csurf');
|
||||
|
||||
chai.use(require('chai-http'));
|
||||
|
||||
const User = require('../../../../models/user');
|
||||
@@ -31,7 +29,6 @@ describe('/api/v1/auth/local', () => {
|
||||
it('should send back the user on a successful login', () => {
|
||||
return chai.request(app)
|
||||
.post('/api/v1/auth/local')
|
||||
.field('_csrf', 'generate csrf token') <--- we need to generate the csrf token that needs to be send from the request
|
||||
.send({email: 'maria@gmail.com', password: 'password!'})
|
||||
.catch((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
|
||||
Reference in New Issue
Block a user