some adjustments to how locking and verification work

This commit is contained in:
Elliot DeNolf
2020-09-26 15:48:08 -04:00
parent 69b4f9f59f
commit 83f77d3a05
12 changed files with 41 additions and 25 deletions

View File

@@ -40,13 +40,14 @@ async function login(args) {
}
const authResult = await userDoc.authenticate(password);
if (authResult.user) {
await authResult.user.resetLoginAttempts();
} else {
await userDoc.incLoginAttempts();
const maxLoginAttemptsEnabled = args.collection.config.auth.maxLoginAttempts > 0;
if (!authResult.user) {
if (maxLoginAttemptsEnabled) await userDoc.incLoginAttempts();
throw new AuthenticationError();
}
if (maxLoginAttemptsEnabled) await authResult.user.resetLoginAttempts();
const userQuery = await operations.collections.find({
where: {
email: {

View File

@@ -13,7 +13,7 @@ import './index.scss';
const baseClass = 'auth-fields';
const Auth = (props) => {
const { useAPIKey, requirePassword } = props;
const { useAPIKey, requirePassword, emailVerification } = props;
const [changingPassword, setChangingPassword] = useState(requirePassword);
const { getField } = useFormFields();
const modified = useFormModified();
@@ -74,6 +74,13 @@ const Auth = (props) => {
)}
</div>
)}
{emailVerification && (
<Checkbox
label="Verified"
name="_verified"
readOnly
/>
)}
</div>
);
};
@@ -81,11 +88,13 @@ const Auth = (props) => {
Auth.defaultProps = {
useAPIKey: false,
requirePassword: false,
emailVerification: false,
};
Auth.propTypes = {
useAPIKey: PropTypes.bool,
requirePassword: PropTypes.bool,
emailVerification: PropTypes.bool,
};
export default Auth;

View File

@@ -91,6 +91,7 @@ const DefaultEditView = (props) => {
<Auth
useAPIKey={auth.useAPIKey}
requirePassword={!isEditing}
emailVerification={auth.emailVerification}
/>
)}
{upload && (
@@ -233,6 +234,7 @@ DefaultEditView.propTypes = {
timestamps: PropTypes.bool,
auth: PropTypes.shape({
useAPIKey: PropTypes.bool,
emailVerification: PropTypes.bool,
}),
upload: PropTypes.shape({}),
}).isRequired,

View File

@@ -24,15 +24,14 @@ function registerCollections() {
usernameField: 'email',
});
// Check if collection is the admin user set in config
if (collection.slug === this.config.admin.user) {
const { maxLoginAttempts, lockTime } = collection.auth;
if (maxLoginAttempts > 0) {
schema.add({ loginAttempts: { type: Number, hide: true, default: 0 } });
schema.add({ lockUntil: { type: Date, hide: true } });
schema.virtual('isLocked').get(() => !!(this.lockUntil && this.lockUntil > Date.now()));
const { maxLoginAttempts, lockTime } = this.config.admin;
// eslint-disable-next-line func-names
schema.methods.incLoginAttempts = function (cb) {
// Expired lock, restart count at 1

View File

@@ -241,13 +241,19 @@ const sanitizeCollection = (collections, collection) => {
authFields.push({
name: '_verified',
type: 'checkbox',
hidden: true,
access: {
create: () => false,
update: () => false,
},
admin: {
disabled: true,
},
});
}
sanitized.auth.maxLoginAttempts = typeof sanitized.auth.maxLoginAttempts === 'undefined' ? 5 : sanitized.auth.maxLoginAttempts;
sanitized.auth.lockTime = sanitized.auth.lockTime || 600000; // 10 minutes
if (!sanitized.auth.tokenExpiration) sanitized.auth.tokenExpiration = 7200;
if (!sanitized.auth.cookies) sanitized.auth.cookies = {};

View File

@@ -5,11 +5,16 @@ const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const qsMiddleware = require('qs-middleware');
const fileUpload = require('express-fileupload');
const rateLimit = require('express-rate-limit');
const localizationMiddleware = require('../../localization/middleware');
const authenticate = require('./authenticate');
const identifyAPI = require('./identifyAPI');
const middleware = (payload) => [
rateLimit({
windowMs: payload.config.rateLimit.window,
max: payload.config.rateLimit.max,
}),
passport.initialize(),
identifyAPI('REST'),
authenticate(payload.config),

View File

@@ -3,7 +3,6 @@ require('isomorphic-fetch');
const express = require('express');
const graphQLPlayground = require('graphql-playground-middleware-express').default;
const rateLimit = require('express-rate-limit');
const logger = require('./utilities/logger')();
const bindOperations = require('./init/bindOperations');
const bindRequestHandlers = require('./init/bindRequestHandlers');
@@ -99,12 +98,8 @@ class Payload {
},
}));
const apiLimiter = rateLimit({
windowMs: this.config.rateLimit.window,
max: this.config.rateLimit.max,
});
// Bind router to API and add rate limiter
this.express.use(this.config.routes.api, apiLimiter, this.router);
// Bind router to API
this.express.use(this.config.routes.api, this.router);
// Enable static routes for all collections permitting upload
this.initStatic();

View File

@@ -29,9 +29,6 @@ const sanitizeConfig = (config) => {
sanitizedConfig.collections.push(defaultUser);
}
sanitizedConfig.maxLoginAttempts = sanitizedConfig.maxLoginAttempts || 3;
sanitizedConfig.lockTime = sanitizedConfig.lockTime || 600000; // 10 minutes
sanitizedConfig.email = config.email || {};
sanitizedConfig.email.fromName = sanitizedConfig.email.fromName || 'Payload';
sanitizedConfig.email.fromAddress = sanitizedConfig.email.fromName || 'hello@payloadcms.com';