Merge pull request #499 from strapi/auth-provider/configs

Auth provider/configs
This commit is contained in:
Jim LAURIE 2018-01-25 13:04:49 +01:00 committed by GitHub
commit a7c9d2bbbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 318 additions and 104 deletions

View File

@ -55,4 +55,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -46,4 +46,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -48,4 +48,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -44,4 +44,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -47,4 +47,4 @@
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -49,4 +49,4 @@
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -17,6 +17,7 @@ module.exports = {
// Default values.
options = _.isObject(options) ? options : {};
options.from = options.from || '"Administration Panel" <no-reply@strapi.io>';
options.replyTo = options.replyTo || '"Administration Panel" <no-reply@strapi.io>';
options.text = options.text || options.html;
options.html = options.html || options.text;
@ -24,6 +25,7 @@ module.exports = {
sendmail({
from: options.from,
to: options.to,
replyTo: options.replyTo,
subject: options.subject,
text: options.text,
html: options.html

View File

@ -48,4 +48,4 @@
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -6,6 +6,8 @@ stats.json
roles.json
jwt.json
grant.json
advanced.json
email.json
# Cruft
.DS_Store

View File

@ -122,6 +122,12 @@
"Policies.header.hint": "Select the application's actions or the plugin's actions and click on the cog icon to display the bounded route",
"Policies.header.title": "Advanced settings",
"Email.template.validation_email": "",
"Email.template.reset_password": "",
"Email.template.success_register": "",
"Auth.advanced.allow_register": "",
"PopUpForm.button.cancel": "Cancel",
"PopUpForm.button.save": "Save",
"PopUpForm.header.add.providers": "Add New Provider",

View File

@ -122,6 +122,12 @@
"Policies.header.hint": "Sélectionnez les actions de l'application ou d'un plugin et cliquer sur l'icon de paramètres pour voir les routes associées à cette action",
"Policies.header.title": "Paramètres avancés",
"Email.template.validation_email": "",
"Email.template.reset_password": "",
"Email.template.success_register": "",
"Auth.advanced.allow_register": "",
"popUpForm.button.cancel": "Annuler",
"popUpForm.button.save": "Sauvegarder",
"popUpForm.header.add.providers": "Ajouter un Nouveau Provider",

View File

@ -21,7 +21,7 @@ module.exports = cb => {
jwtSecret
}, null, 2), 'utf8');
_.set(strapi.plugins['users-permissions'], 'config.jwtSecret', jwtSecret);
_.set(strapi.plugins['users-permissions'], 'config.jwtSecret', jwtSecret);
} catch(err) {
strapi.log.error(err);
}
@ -30,19 +30,25 @@ module.exports = cb => {
if (!_.get(strapi.plugins['users-permissions'], 'config.grant')) {
try {
const grant = {
local: {
enabled: true
},
facebook: {
enabled: false,
key: '',
secret: '',
callback: '/auth/facebook/callback',
scope: ['email']
},
google: {
enabled: false,
key: '',
secret: '',
callback: '/auth/google/callback',
scope: ['email']
},
github: {
enabled: false,
key: '',
secret: '',
redirect_uri: '/auth/google/callback',
@ -52,6 +58,7 @@ module.exports = cb => {
]
},
twitter: {
enabled: false,
key: '',
secret: '',
callback: '/auth/twitter/callback'
@ -68,6 +75,83 @@ module.exports = cb => {
}
}
if (!_.get(strapi.plugins['users-permissions'], 'config.email')) {
try {
const email = {
'validation_email': {
display: 'Email.template.validation_email',
icon: 'envelope',
options: {
from: {
email: '',
name: ''
},
respond: '',
object: '',
message: ''
}
},
'reset_password': {
display: 'Email.template.reset_password',
icon: 'refresh',
options: {
from: {
email: '',
name: ''
},
respond: '',
object: '­Reset password 🔑 ',
message: `<p>We heard that you lost your password. Sorry about that!</p>
<p>But dont worry! You can use the following link to reset your password:</p>
<p><%= url %>?code=<%= token %></p>
<p>Thanks.</p>`
}
},
'success_register': {
display: 'Email.template.success_register',
icon: 'check',
options: {
from: {
email: '',
name: ''
},
respond: '',
object: '',
message: ''
}
}
};
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'email.json'), JSON.stringify({
email
}, null, 2), 'utf8');
_.set(strapi.plugins['users-permissions'], 'config.email', email);
} catch(err) {
strapi.log.error(err);
}
}
if (!_.get(strapi.plugins['users-permissions'], 'config.advanced')) {
try {
const advanced = {
unique_email: true,
allow_register: true
};
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'advanced.json'), JSON.stringify({
advanced
}, null, 2), 'utf8');
_.set(strapi.plugins['users-permissions'], 'config.advanced', advanced);
} catch(err) {
strapi.log.error(err);
}
}
strapi.plugins['users-permissions'].services.userspermissions.syncSchema(() => {
strapi.plugins['users-permissions'].services.userspermissions.updatePermissions(cb);
});

View File

@ -64,6 +64,39 @@
"policies": []
}
},
{
"method": "GET",
"path": "/email-template",
"handler": "UsersPermissions.getEmailTemplate",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/email-template",
"handler": "UsersPermissions.updateEmailTemplate",
"config": {
"policies": []
}
},
{
"method": "GET",
"path": "/advanced",
"handler": "UsersPermissions.getAdvancedSettings",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/advanced",
"handler": "UsersPermissions.updateAdvancedSettings",
"config": {
"policies": []
}
},
{
"method": "POST",
@ -98,6 +131,15 @@
}
},
{
"method": "GET",
"path": "/connect/*",
"handler": "Auth.connect",
"config": {
"policies": [],
"prefix": ""
}
},
{
"method": "POST",
"path": "/auth/local",

View File

@ -8,6 +8,7 @@
const _ = require('lodash');
const crypto = require('crypto');
const Grant = require('grant-koa');
const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
module.exports = {
@ -16,6 +17,10 @@ module.exports = {
const params = ctx.request.body;
if (provider === 'local') {
if (!_.get(strapi.plugins['users-permissions'].config.grant[provider], 'enabled') && !ctx.request.admin) {
return ctx.badRequest(null, 'This provider is disabled.');
}
// The identifier is required.
if (!params.identifier) {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Auth.form.error.email.provide' }] }] : 'Please provide your username or your e-mail.');
@ -62,7 +67,11 @@ module.exports = {
}
} else {
// Connect the user thanks to the third-party provider.
const user = await strapi.plugins['users-permissions'].services.providers.connect(provider, ctx.query);
const [user, error] = await strapi.plugins['users-permissions'].services.providers.connect(provider, ctx.query);
if (error) {
return ctx.badRequest(null, (error === 'array') ? (ctx.request.admin ? error[0] : error[1]) : error);
}
ctx.send({
jwt: strapi.plugins['users-permissions'].services.jwt.issue(user),
@ -100,6 +109,26 @@ module.exports = {
}
},
connect: async (ctx, next) => {
_.defaultsDeep(strapi.plugins['users-permissions'].config.grant, {
server: {
protocol: 'http',
host: `${strapi.config.currentEnvironment.server.host}:${strapi.config.currentEnvironment.server.port}`
}
});
const provider = ctx.request.url.split('/')[2];
const config = strapi.plugins['users-permissions'].config.grant[provider];
if (!_.get(config, 'enabled')) {
return ctx.badRequest(null, 'This provider is disabled.');
}
const grant = new Grant(strapi.plugins['users-permissions'].config.grant);
return strapi.koaMiddlewares.compose(grant.middleware)(ctx, next);
},
forgotPassword: async (ctx) => {
const { email, url } = ctx.request.body;
@ -117,23 +146,27 @@ module.exports = {
// Set the property code.
user.resetPasswordToken = resetPasswordToken;
// Send an email to the user.
const template = `
<p>We heard that you lost your password. Sorry about that!</p>
const settings = strapi.plugins['users-permissions'].config.email['reset_password'].options;
<p>But dont worry! You can use the following link to reset your password:</p>
settings.message = await strapi.plugins['users-permissions'].services.userspermissions.template(settings.message, {
url,
user: _.omit(user.toJSON(), ['password', 'resetPasswordToken', 'role', 'provider']),
token: resetPasswordToken
});
<p>${url}?code=${resetPasswordToken}</p>
<p>Thanks.</p>
`;
settings.object = await strapi.plugins['users-permissions'].services.userspermissions.template(settings.object, {
user: _.omit(user.toJSON(), ['password', 'resetPasswordToken', 'role', 'provider'])
});
try {
// Send an email to the user.
await strapi.plugins['email'].services.email.send({
to: user.email,
subject: '­Reset password 🔑 ',
text: template,
html: template
from: (settings.from.email || settings.from.name) ? `"${settings.from.name}" <${settings.from.email}>` : undefined,
replyTo: settings.respond,
subject: settings.object,
text: settings.message,
html: settings.message
});
} catch (err) {
return ctx.badRequest(null, err);
@ -146,6 +179,10 @@ module.exports = {
},
register: async (ctx) => {
if (!strapi.plugins['users-permissions'].config.advanced.allow_register) {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Auth.advanced.allow_register' }] }] : 'Register action is actualy not available.');
}
const params = _.assign(ctx.request.body, {
provider: 'local'
});
@ -178,6 +215,18 @@ module.exports = {
}
params.password = await strapi.plugins['users-permissions'].services.user.hashPassword(params);
const user = await strapi.query('user', 'users-permissions').findOne({
email: params.email
});
if (user && user.provider === params.provider) {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Auth.form.error.email.taken' }] }] : 'Email is already taken.');
}
if (user && user.provider !== params.provider && strapi.plugins['users-permissions'].config.advanced.unique_email) {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Auth.form.error.email.taken' }] }] : 'Email is already taken.');
}
try {
const user = await strapi.query('user', 'users-permissions').create(params);

View File

@ -39,7 +39,7 @@ module.exports = {
if (!user) {
return ctx.badRequest(null, [{ messages: [{ id: 'No authorization header was found' }] }]);
}
const data = _.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken']);
// Send 200 `ok`
@ -98,6 +98,16 @@ module.exports = {
delete ctx.request.body.role;
}
if (ctx.request.body.email && strapi.plugins['users-permissions'].config.advanced.unique_email) {
const user = await strapi.query('user', 'users-permissions').findOne({
email: ctx.request.body.email
});
if (user.id !== ctx.params.id) {
return ctx.badRequest(null, ctx.request.admin ? [{ messages: [{ id: 'Auth.form.error.email.taken' }] }] : 'Email is already taken.');
}
}
const data = await strapi.plugins['users-permissions'].services.user.edit(ctx.params, ctx.request.body) ;
// Send 200 `ok`

View File

@ -6,6 +6,9 @@
* @description: A set of functions called "actions" of the `users-permissions` plugin.
*/
const path = require('path');
const fs = require('fs');
const _ = require('lodash');
module.exports = {
@ -160,5 +163,41 @@ module.exports = {
} catch(error) {
ctx.badRequest(null, [{ messages: [{ id: 'An error occurred' }] }]);
}
},
getEmailTemplate: async (ctx) => {
ctx.send(strapi.plugins['users-permissions'].config.email);
},
updateEmailTemplate: async (ctx) => {
if (_.isEmpty(ctx.request.body)) {
return ctx.badRequest(null, [{ messages: [{ id: 'Cannot be empty' }] }]);
}
strapi.plugins['users-permissions'].config.email = ctx.request.body;
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'email.json'), JSON.stringify({
email: strapi.plugins['users-permissions'].config.email
}, null, 2), 'utf8');
return ctx.send({ ok: true });
},
getAdvancedSettings: async (ctx) => {
ctx.send(strapi.plugins['users-permissions'].config.advanced);
},
updateAdvancedSettings: async (ctx) => {
if (_.isEmpty(ctx.request.body)) {
return ctx.badRequest(null, [{ messages: [{ id: 'Cannot be empty' }] }]);
}
strapi.plugins['users-permissions'].config.advanced = ctx.request.body;
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'advanced.json'), JSON.stringify({
email: strapi.plugins['users-permissions'].config.advanced
}, null, 2), 'utf8');
return ctx.send({ ok: true });
}
};

View File

@ -1,5 +0,0 @@
{
"provider": {
"enabled": true
}
}

View File

@ -1,32 +0,0 @@
'use strict';
/**
* Module dependencies
*/
// Public node modules.
const _ = require('lodash');
const Grant = require('grant-koa');
module.exports = strapi => {
return {
beforeInitialize: function() {
strapi.config.middleware.load.after.push('provider');
},
initialize: function(cb) {
_.defaultsDeep(strapi.plugins['users-permissions'].config.grant, {
server: {
protocol: 'http',
host: 'localhost:1337'
}
});
const grant = new Grant(strapi.plugins['users-permissions'].config.grant);
strapi.app.use(strapi.koaMiddlewares.compose(grant.middleware));
cb();
}
};
};

View File

@ -15,7 +15,6 @@
"email": {
"type": "email",
"minLength": 6,
"unique": true,
"configurable": false,
"required": true
},

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-users-permissions",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Protect your API with a full-authentication process based on JWT",
"strapi": {
"name": "Auth & Permissions",
@ -55,4 +55,4 @@
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -47,47 +47,54 @@ exports.connect = (provider, query) => {
return new Promise((resolve, reject) => {
if (!access_token) {
reject({
return reject(null, {
message: 'No access_token.'
});
} else {
// Get the profile.
getProfile(provider, query, (err, profile) => {
if (err) {
reject(err);
} else {
// We need at least the mail.
if (!profile.email) {
reject({
message: 'Email was not available.'
});
} else {
strapi.query('user', 'users-permissions').findOne({email: profile.email})
.then(user => {
if (!user) {
// Create the new user.
const params = _.assign(profile, {
provider: provider
});
strapi.query('user', 'users-permissions').create(params)
.then(user => {
resolve(user);
})
.catch(err => {
reject(err);
});
} else {
resolve(user);
}
})
.catch(err => {
reject(err);
});
}
}
});
}
// Get the profile.
getProfile(provider, query, async (err, profile) => {
if (err) {
return reject(err);
}
// We need at least the mail.
if (!profile.email) {
return reject([{
message: 'Email was not available.'
}, null]);
}
try {
const user = await strapi.query('user', 'users-permissions').findOne({email: profile.email});
if (!strapi.plugins['users-permissions'].config.advanced.allow_register) {
return resolve([null, [{ messages: [{ id: 'Auth.advanced.allow_register' }] }], 'Register action is actualy not available.']);
}
if (user && user.provider === provider) {
return resolve([null, [{ messages: [{ id: 'Auth.form.error.email.taken' }] }], 'Email is already taken.']);
}
if (user && user.provider !== provider && strapi.plugins['users-permissions'].config.advanced.unique_email) {
return resolve([null, [{ messages: [{ id: 'Auth.form.error.email.taken' }] }], 'Email is already taken.']);
}
if (!user || _.get(user, 'provider') !== provider) {
// Create the new user.
const params = _.assign(profile, {
provider: provider
});
const createdUser = await strapi.query('user', 'users-permissions').create(params);
return resolve([createdUser, null]);
}
resolve([user, null]);
} catch (err) {
reject([null, err]);
}
});
});
};

View File

@ -345,5 +345,10 @@ ${commands}
cb();
});
});
},
template: (layout, data) => {
const compiledObject = _.template(layout);
return compiledObject(data);
}
};