@strapi/plugin-users-permissions 5.47.1 → 5.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -59,8 +59,12 @@ function requireUser() {
59
59
  * Promise to add a/an user.
60
60
  * @return {Promise}
61
61
  */ async add (values) {
62
- return strapi1.db.query(USER_MODEL_UID).create({
63
- data: await this.ensureHashedPasswords(values),
62
+ // Use the Document Service so relation inputs accept both the internal
63
+ // numeric id (legacy) and the documentId (v5 default) syntax, consistent
64
+ // with every other content-type endpoint. The Document Service hashes
65
+ // `password` attributes itself, so we must not pre-hash here.
66
+ return strapi1.documents(USER_MODEL_UID).create({
67
+ data: values,
64
68
  populate: [
65
69
  'role'
66
70
  ]
@@ -72,11 +76,25 @@ function requireUser() {
72
76
  * @param {object} params
73
77
  * @return {Promise}
74
78
  */ async edit (userId, params = {}) {
75
- return strapi1.db.query(USER_MODEL_UID).update({
79
+ // The user is addressed by its numeric id (e.g. the `/users/:id` route),
80
+ // but the Document Service updates by documentId. Resolve it first so the
81
+ // relation inputs are processed by the Document Service, which accepts both
82
+ // numeric ids (legacy) and documentIds (v5 default). The Document Service
83
+ // hashes `password` attributes itself, so we must not pre-hash here.
84
+ const entry = await strapi1.db.query(USER_MODEL_UID).findOne({
76
85
  where: {
77
86
  id: userId
78
87
  },
79
- data: await this.ensureHashedPasswords(params),
88
+ select: [
89
+ 'documentId'
90
+ ]
91
+ });
92
+ if (!entry) {
93
+ return null;
94
+ }
95
+ return strapi1.documents(USER_MODEL_UID).update({
96
+ documentId: entry.documentId,
97
+ data: params,
80
98
  populate: [
81
99
  'role'
82
100
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"user.js","sources":["../../../server/services/user.js"],"sourcesContent":["'use strict';\n\n/**\n * User.js service\n *\n * @description: A set of functions similar to controller's actions to avoid code duplication.\n */\n\nconst crypto = require('crypto');\nconst bcrypt = require('bcryptjs');\nconst urlJoin = require('url-join');\n\nconst { sanitize } = require('@strapi/utils');\nconst { toNumber, getOr } = require('lodash/fp');\nconst { getService } = require('../utils');\n\nconst USER_MODEL_UID = 'plugin::users-permissions.user';\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\nmodule.exports = ({ strapi }) => ({\n /**\n * Promise to count users\n *\n * @return {Promise}\n */\n\n count(params) {\n return strapi.db.query(USER_MODEL_UID).count({ where: params });\n },\n\n /**\n * Hashes password fields in the provided values object if they are present.\n * It checks each key in the values object against the model's attributes and\n * hashes it if the attribute type is 'password',\n *\n * @param {object} values - The object containing the fields to be hashed.\n * @return {object} The values object with hashed password fields if they were present.\n */\n async ensureHashedPasswords(values) {\n const attributes = strapi.getModel(USER_MODEL_UID).attributes;\n\n for (const key in values) {\n if (attributes[key] && attributes[key].type === 'password') {\n // Check if a custom encryption.rounds has been set on the password attribute\n const rounds = toNumber(getOr(10, 'encryption.rounds', attributes[key]));\n values[key] = await bcrypt.hash(values[key], rounds);\n }\n }\n\n return values;\n },\n\n /**\n * Promise to add a/an user.\n * @return {Promise}\n */\n async add(values) {\n return strapi.db.query(USER_MODEL_UID).create({\n data: await this.ensureHashedPasswords(values),\n populate: ['role'],\n });\n },\n\n /**\n * Promise to edit a/an user.\n * @param {string} userId\n * @param {object} params\n * @return {Promise}\n */\n async edit(userId, params = {}) {\n return strapi.db.query(USER_MODEL_UID).update({\n where: { id: userId },\n data: await this.ensureHashedPasswords(params),\n populate: ['role'],\n });\n },\n\n /**\n * Promise to fetch a/an user.\n * @return {Promise}\n */\n fetch(id, params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findOne({\n ...query,\n where: {\n $and: [{ id }, query.where || {}],\n },\n });\n },\n\n /**\n * Promise to fetch authenticated user.\n * @return {Promise}\n */\n fetchAuthenticatedUser(id) {\n return strapi.db.query(USER_MODEL_UID).findOne({ where: { id }, populate: ['role'] });\n },\n\n /**\n * Promise to fetch all users.\n * @return {Promise}\n */\n fetchAll(params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findMany(query);\n },\n\n /**\n * Promise to remove a/an user.\n * @return {Promise}\n */\n async remove(params) {\n // Invalidate sessions for all affected users\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('users-permissions') && params.id) {\n await sessionManager('users-permissions').invalidateRefreshToken(String(params.id));\n }\n\n return strapi.db.query(USER_MODEL_UID).delete({ where: params });\n },\n\n validatePassword(password, hash) {\n return bcrypt.compare(password, hash);\n },\n\n async sendConfirmationEmail(user) {\n const userPermissionService = getService('users-permissions');\n const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });\n const userSchema = strapi.getModel(USER_MODEL_UID);\n\n const settings = await pluginStore\n .get({ key: 'email' })\n .then((storeEmail) => storeEmail.email_confirmation.options);\n\n // Sanitize the template's user information\n const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(\n {\n schema: userSchema,\n getModel: strapi.getModel.bind(strapi),\n },\n user\n );\n\n const confirmationToken = crypto.randomBytes(20).toString('hex');\n\n await this.edit(user.id, { confirmationToken });\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n\n try {\n settings.message = await userPermissionService.template(settings.message, {\n URL: urlJoin(\n strapi.config.get('server.absoluteUrl'),\n apiPrefix,\n '/auth/email-confirmation'\n ),\n SERVER_URL: strapi.config.get('server.absoluteUrl'),\n ADMIN_URL: strapi.config.get('admin.absoluteUrl'),\n USER: sanitizedUserInfo,\n CODE: confirmationToken,\n });\n\n settings.object = await userPermissionService.template(settings.object, {\n USER: sanitizedUserInfo,\n });\n } catch {\n strapi.log.error(\n '[plugin::users-permissions.sendConfirmationEmail]: Failed to generate a template for \"user confirmation email\". Please make sure your email template is valid and does not contain invalid characters or patterns'\n );\n return;\n }\n\n // Send an email to the user.\n await strapi\n .plugin('email')\n .service('email')\n .send({\n to: user.email,\n from:\n settings.from.email && settings.from.name\n ? `${settings.from.name} <${settings.from.email}>`\n : undefined,\n replyTo: settings.response_email,\n subject: settings.object,\n text: settings.message,\n html: settings.message,\n });\n },\n});\n"],"names":["crypto","require$$0","bcrypt","require$$1","urlJoin","require$$2","sanitize","require$$3","toNumber","getOr","require$$4","getService","require$$5","USER_MODEL_UID","getSessionManager","manager","strapi","sessionManager","user","count","params","db","query","where","ensureHashedPasswords","values","attributes","getModel","key","type","rounds","hash","add","create","data","populate","edit","userId","update","id","fetch","get","transform","findOne","$and","fetchAuthenticatedUser","fetchAll","findMany","remove","hasOrigin","invalidateRefreshToken","String","delete","validatePassword","password","compare","sendConfirmationEmail","userPermissionService","pluginStore","store","name","userSchema","settings","then","storeEmail","email_confirmation","options","sanitizedUserInfo","sanitizers","defaultSanitizeOutput","schema","bind","confirmationToken","randomBytes","toString","apiPrefix","config","message","template","URL","SERVER_URL","ADMIN_URL","USER","CODE","object","log","error","plugin","service","send","to","email","from","undefined","replyTo","response_email","subject","text","html"],"mappings":"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"}
1
+ {"version":3,"file":"user.js","sources":["../../../server/services/user.js"],"sourcesContent":["'use strict';\n\n/**\n * User.js service\n *\n * @description: A set of functions similar to controller's actions to avoid code duplication.\n */\n\nconst crypto = require('crypto');\nconst bcrypt = require('bcryptjs');\nconst urlJoin = require('url-join');\n\nconst { sanitize } = require('@strapi/utils');\nconst { toNumber, getOr } = require('lodash/fp');\nconst { getService } = require('../utils');\n\nconst USER_MODEL_UID = 'plugin::users-permissions.user';\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\nmodule.exports = ({ strapi }) => ({\n /**\n * Promise to count users\n *\n * @return {Promise}\n */\n\n count(params) {\n return strapi.db.query(USER_MODEL_UID).count({ where: params });\n },\n\n /**\n * Hashes password fields in the provided values object if they are present.\n * It checks each key in the values object against the model's attributes and\n * hashes it if the attribute type is 'password',\n *\n * @param {object} values - The object containing the fields to be hashed.\n * @return {object} The values object with hashed password fields if they were present.\n */\n async ensureHashedPasswords(values) {\n const attributes = strapi.getModel(USER_MODEL_UID).attributes;\n\n for (const key in values) {\n if (attributes[key] && attributes[key].type === 'password') {\n // Check if a custom encryption.rounds has been set on the password attribute\n const rounds = toNumber(getOr(10, 'encryption.rounds', attributes[key]));\n values[key] = await bcrypt.hash(values[key], rounds);\n }\n }\n\n return values;\n },\n\n /**\n * Promise to add a/an user.\n * @return {Promise}\n */\n async add(values) {\n // Use the Document Service so relation inputs accept both the internal\n // numeric id (legacy) and the documentId (v5 default) syntax, consistent\n // with every other content-type endpoint. The Document Service hashes\n // `password` attributes itself, so we must not pre-hash here.\n return strapi.documents(USER_MODEL_UID).create({\n data: values,\n populate: ['role'],\n });\n },\n\n /**\n * Promise to edit a/an user.\n * @param {string} userId\n * @param {object} params\n * @return {Promise}\n */\n async edit(userId, params = {}) {\n // The user is addressed by its numeric id (e.g. the `/users/:id` route),\n // but the Document Service updates by documentId. Resolve it first so the\n // relation inputs are processed by the Document Service, which accepts both\n // numeric ids (legacy) and documentIds (v5 default). The Document Service\n // hashes `password` attributes itself, so we must not pre-hash here.\n const entry = await strapi.db\n .query(USER_MODEL_UID)\n .findOne({ where: { id: userId }, select: ['documentId'] });\n\n if (!entry) {\n return null;\n }\n\n return strapi.documents(USER_MODEL_UID).update({\n documentId: entry.documentId,\n data: params,\n populate: ['role'],\n });\n },\n\n /**\n * Promise to fetch a/an user.\n * @return {Promise}\n */\n fetch(id, params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findOne({\n ...query,\n where: {\n $and: [{ id }, query.where || {}],\n },\n });\n },\n\n /**\n * Promise to fetch authenticated user.\n * @return {Promise}\n */\n fetchAuthenticatedUser(id) {\n return strapi.db.query(USER_MODEL_UID).findOne({ where: { id }, populate: ['role'] });\n },\n\n /**\n * Promise to fetch all users.\n * @return {Promise}\n */\n fetchAll(params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findMany(query);\n },\n\n /**\n * Promise to remove a/an user.\n * @return {Promise}\n */\n async remove(params) {\n // Invalidate sessions for all affected users\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('users-permissions') && params.id) {\n await sessionManager('users-permissions').invalidateRefreshToken(String(params.id));\n }\n\n return strapi.db.query(USER_MODEL_UID).delete({ where: params });\n },\n\n validatePassword(password, hash) {\n return bcrypt.compare(password, hash);\n },\n\n async sendConfirmationEmail(user) {\n const userPermissionService = getService('users-permissions');\n const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });\n const userSchema = strapi.getModel(USER_MODEL_UID);\n\n const settings = await pluginStore\n .get({ key: 'email' })\n .then((storeEmail) => storeEmail.email_confirmation.options);\n\n // Sanitize the template's user information\n const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(\n {\n schema: userSchema,\n getModel: strapi.getModel.bind(strapi),\n },\n user\n );\n\n const confirmationToken = crypto.randomBytes(20).toString('hex');\n\n await this.edit(user.id, { confirmationToken });\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n\n try {\n settings.message = await userPermissionService.template(settings.message, {\n URL: urlJoin(\n strapi.config.get('server.absoluteUrl'),\n apiPrefix,\n '/auth/email-confirmation'\n ),\n SERVER_URL: strapi.config.get('server.absoluteUrl'),\n ADMIN_URL: strapi.config.get('admin.absoluteUrl'),\n USER: sanitizedUserInfo,\n CODE: confirmationToken,\n });\n\n settings.object = await userPermissionService.template(settings.object, {\n USER: sanitizedUserInfo,\n });\n } catch {\n strapi.log.error(\n '[plugin::users-permissions.sendConfirmationEmail]: Failed to generate a template for \"user confirmation email\". Please make sure your email template is valid and does not contain invalid characters or patterns'\n );\n return;\n }\n\n // Send an email to the user.\n await strapi\n .plugin('email')\n .service('email')\n .send({\n to: user.email,\n from:\n settings.from.email && settings.from.name\n ? `${settings.from.name} <${settings.from.email}>`\n : undefined,\n replyTo: settings.response_email,\n subject: settings.object,\n text: settings.message,\n html: settings.message,\n });\n },\n});\n"],"names":["crypto","require$$0","bcrypt","require$$1","urlJoin","require$$2","sanitize","require$$3","toNumber","getOr","require$$4","getService","require$$5","USER_MODEL_UID","getSessionManager","manager","strapi","sessionManager","user","count","params","db","query","where","ensureHashedPasswords","values","attributes","getModel","key","type","rounds","hash","add","documents","create","data","populate","edit","userId","entry","findOne","id","select","update","documentId","fetch","get","transform","$and","fetchAuthenticatedUser","fetchAll","findMany","remove","hasOrigin","invalidateRefreshToken","String","delete","validatePassword","password","compare","sendConfirmationEmail","userPermissionService","pluginStore","store","name","userSchema","settings","then","storeEmail","email_confirmation","options","sanitizedUserInfo","sanitizers","defaultSanitizeOutput","schema","bind","confirmationToken","randomBytes","toString","apiPrefix","config","message","template","URL","SERVER_URL","ADMIN_URL","USER","CODE","object","log","error","plugin","service","send","to","email","from","undefined","replyTo","response_email","subject","text","html"],"mappings":"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"}
@@ -57,8 +57,12 @@ function requireUser() {
57
57
  * Promise to add a/an user.
58
58
  * @return {Promise}
59
59
  */ async add (values) {
60
- return strapi1.db.query(USER_MODEL_UID).create({
61
- data: await this.ensureHashedPasswords(values),
60
+ // Use the Document Service so relation inputs accept both the internal
61
+ // numeric id (legacy) and the documentId (v5 default) syntax, consistent
62
+ // with every other content-type endpoint. The Document Service hashes
63
+ // `password` attributes itself, so we must not pre-hash here.
64
+ return strapi1.documents(USER_MODEL_UID).create({
65
+ data: values,
62
66
  populate: [
63
67
  'role'
64
68
  ]
@@ -70,11 +74,25 @@ function requireUser() {
70
74
  * @param {object} params
71
75
  * @return {Promise}
72
76
  */ async edit (userId, params = {}) {
73
- return strapi1.db.query(USER_MODEL_UID).update({
77
+ // The user is addressed by its numeric id (e.g. the `/users/:id` route),
78
+ // but the Document Service updates by documentId. Resolve it first so the
79
+ // relation inputs are processed by the Document Service, which accepts both
80
+ // numeric ids (legacy) and documentIds (v5 default). The Document Service
81
+ // hashes `password` attributes itself, so we must not pre-hash here.
82
+ const entry = await strapi1.db.query(USER_MODEL_UID).findOne({
74
83
  where: {
75
84
  id: userId
76
85
  },
77
- data: await this.ensureHashedPasswords(params),
86
+ select: [
87
+ 'documentId'
88
+ ]
89
+ });
90
+ if (!entry) {
91
+ return null;
92
+ }
93
+ return strapi1.documents(USER_MODEL_UID).update({
94
+ documentId: entry.documentId,
95
+ data: params,
78
96
  populate: [
79
97
  'role'
80
98
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"user.mjs","sources":["../../../server/services/user.js"],"sourcesContent":["'use strict';\n\n/**\n * User.js service\n *\n * @description: A set of functions similar to controller's actions to avoid code duplication.\n */\n\nconst crypto = require('crypto');\nconst bcrypt = require('bcryptjs');\nconst urlJoin = require('url-join');\n\nconst { sanitize } = require('@strapi/utils');\nconst { toNumber, getOr } = require('lodash/fp');\nconst { getService } = require('../utils');\n\nconst USER_MODEL_UID = 'plugin::users-permissions.user';\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\nmodule.exports = ({ strapi }) => ({\n /**\n * Promise to count users\n *\n * @return {Promise}\n */\n\n count(params) {\n return strapi.db.query(USER_MODEL_UID).count({ where: params });\n },\n\n /**\n * Hashes password fields in the provided values object if they are present.\n * It checks each key in the values object against the model's attributes and\n * hashes it if the attribute type is 'password',\n *\n * @param {object} values - The object containing the fields to be hashed.\n * @return {object} The values object with hashed password fields if they were present.\n */\n async ensureHashedPasswords(values) {\n const attributes = strapi.getModel(USER_MODEL_UID).attributes;\n\n for (const key in values) {\n if (attributes[key] && attributes[key].type === 'password') {\n // Check if a custom encryption.rounds has been set on the password attribute\n const rounds = toNumber(getOr(10, 'encryption.rounds', attributes[key]));\n values[key] = await bcrypt.hash(values[key], rounds);\n }\n }\n\n return values;\n },\n\n /**\n * Promise to add a/an user.\n * @return {Promise}\n */\n async add(values) {\n return strapi.db.query(USER_MODEL_UID).create({\n data: await this.ensureHashedPasswords(values),\n populate: ['role'],\n });\n },\n\n /**\n * Promise to edit a/an user.\n * @param {string} userId\n * @param {object} params\n * @return {Promise}\n */\n async edit(userId, params = {}) {\n return strapi.db.query(USER_MODEL_UID).update({\n where: { id: userId },\n data: await this.ensureHashedPasswords(params),\n populate: ['role'],\n });\n },\n\n /**\n * Promise to fetch a/an user.\n * @return {Promise}\n */\n fetch(id, params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findOne({\n ...query,\n where: {\n $and: [{ id }, query.where || {}],\n },\n });\n },\n\n /**\n * Promise to fetch authenticated user.\n * @return {Promise}\n */\n fetchAuthenticatedUser(id) {\n return strapi.db.query(USER_MODEL_UID).findOne({ where: { id }, populate: ['role'] });\n },\n\n /**\n * Promise to fetch all users.\n * @return {Promise}\n */\n fetchAll(params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findMany(query);\n },\n\n /**\n * Promise to remove a/an user.\n * @return {Promise}\n */\n async remove(params) {\n // Invalidate sessions for all affected users\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('users-permissions') && params.id) {\n await sessionManager('users-permissions').invalidateRefreshToken(String(params.id));\n }\n\n return strapi.db.query(USER_MODEL_UID).delete({ where: params });\n },\n\n validatePassword(password, hash) {\n return bcrypt.compare(password, hash);\n },\n\n async sendConfirmationEmail(user) {\n const userPermissionService = getService('users-permissions');\n const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });\n const userSchema = strapi.getModel(USER_MODEL_UID);\n\n const settings = await pluginStore\n .get({ key: 'email' })\n .then((storeEmail) => storeEmail.email_confirmation.options);\n\n // Sanitize the template's user information\n const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(\n {\n schema: userSchema,\n getModel: strapi.getModel.bind(strapi),\n },\n user\n );\n\n const confirmationToken = crypto.randomBytes(20).toString('hex');\n\n await this.edit(user.id, { confirmationToken });\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n\n try {\n settings.message = await userPermissionService.template(settings.message, {\n URL: urlJoin(\n strapi.config.get('server.absoluteUrl'),\n apiPrefix,\n '/auth/email-confirmation'\n ),\n SERVER_URL: strapi.config.get('server.absoluteUrl'),\n ADMIN_URL: strapi.config.get('admin.absoluteUrl'),\n USER: sanitizedUserInfo,\n CODE: confirmationToken,\n });\n\n settings.object = await userPermissionService.template(settings.object, {\n USER: sanitizedUserInfo,\n });\n } catch {\n strapi.log.error(\n '[plugin::users-permissions.sendConfirmationEmail]: Failed to generate a template for \"user confirmation email\". Please make sure your email template is valid and does not contain invalid characters or patterns'\n );\n return;\n }\n\n // Send an email to the user.\n await strapi\n .plugin('email')\n .service('email')\n .send({\n to: user.email,\n from:\n settings.from.email && settings.from.name\n ? `${settings.from.name} <${settings.from.email}>`\n : undefined,\n replyTo: settings.response_email,\n subject: settings.object,\n text: settings.message,\n html: settings.message,\n });\n },\n});\n"],"names":["crypto","require$$0","bcrypt","require$$1","urlJoin","require$$2","sanitize","require$$3","toNumber","getOr","require$$4","getService","require$$5","USER_MODEL_UID","getSessionManager","manager","strapi","sessionManager","user","count","params","db","query","where","ensureHashedPasswords","values","attributes","getModel","key","type","rounds","hash","add","create","data","populate","edit","userId","update","id","fetch","get","transform","findOne","$and","fetchAuthenticatedUser","fetchAll","findMany","remove","hasOrigin","invalidateRefreshToken","String","delete","validatePassword","password","compare","sendConfirmationEmail","userPermissionService","pluginStore","store","name","userSchema","settings","then","storeEmail","email_confirmation","options","sanitizedUserInfo","sanitizers","defaultSanitizeOutput","schema","bind","confirmationToken","randomBytes","toString","apiPrefix","config","message","template","URL","SERVER_URL","ADMIN_URL","USER","CODE","object","log","error","plugin","service","send","to","email","from","undefined","replyTo","response_email","subject","text","html"],"mappings":"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"}
1
+ {"version":3,"file":"user.mjs","sources":["../../../server/services/user.js"],"sourcesContent":["'use strict';\n\n/**\n * User.js service\n *\n * @description: A set of functions similar to controller's actions to avoid code duplication.\n */\n\nconst crypto = require('crypto');\nconst bcrypt = require('bcryptjs');\nconst urlJoin = require('url-join');\n\nconst { sanitize } = require('@strapi/utils');\nconst { toNumber, getOr } = require('lodash/fp');\nconst { getService } = require('../utils');\n\nconst USER_MODEL_UID = 'plugin::users-permissions.user';\n\nconst getSessionManager = () => {\n const manager = strapi.sessionManager;\n return manager ?? null;\n};\n\nmodule.exports = ({ strapi }) => ({\n /**\n * Promise to count users\n *\n * @return {Promise}\n */\n\n count(params) {\n return strapi.db.query(USER_MODEL_UID).count({ where: params });\n },\n\n /**\n * Hashes password fields in the provided values object if they are present.\n * It checks each key in the values object against the model's attributes and\n * hashes it if the attribute type is 'password',\n *\n * @param {object} values - The object containing the fields to be hashed.\n * @return {object} The values object with hashed password fields if they were present.\n */\n async ensureHashedPasswords(values) {\n const attributes = strapi.getModel(USER_MODEL_UID).attributes;\n\n for (const key in values) {\n if (attributes[key] && attributes[key].type === 'password') {\n // Check if a custom encryption.rounds has been set on the password attribute\n const rounds = toNumber(getOr(10, 'encryption.rounds', attributes[key]));\n values[key] = await bcrypt.hash(values[key], rounds);\n }\n }\n\n return values;\n },\n\n /**\n * Promise to add a/an user.\n * @return {Promise}\n */\n async add(values) {\n // Use the Document Service so relation inputs accept both the internal\n // numeric id (legacy) and the documentId (v5 default) syntax, consistent\n // with every other content-type endpoint. The Document Service hashes\n // `password` attributes itself, so we must not pre-hash here.\n return strapi.documents(USER_MODEL_UID).create({\n data: values,\n populate: ['role'],\n });\n },\n\n /**\n * Promise to edit a/an user.\n * @param {string} userId\n * @param {object} params\n * @return {Promise}\n */\n async edit(userId, params = {}) {\n // The user is addressed by its numeric id (e.g. the `/users/:id` route),\n // but the Document Service updates by documentId. Resolve it first so the\n // relation inputs are processed by the Document Service, which accepts both\n // numeric ids (legacy) and documentIds (v5 default). The Document Service\n // hashes `password` attributes itself, so we must not pre-hash here.\n const entry = await strapi.db\n .query(USER_MODEL_UID)\n .findOne({ where: { id: userId }, select: ['documentId'] });\n\n if (!entry) {\n return null;\n }\n\n return strapi.documents(USER_MODEL_UID).update({\n documentId: entry.documentId,\n data: params,\n populate: ['role'],\n });\n },\n\n /**\n * Promise to fetch a/an user.\n * @return {Promise}\n */\n fetch(id, params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findOne({\n ...query,\n where: {\n $and: [{ id }, query.where || {}],\n },\n });\n },\n\n /**\n * Promise to fetch authenticated user.\n * @return {Promise}\n */\n fetchAuthenticatedUser(id) {\n return strapi.db.query(USER_MODEL_UID).findOne({ where: { id }, populate: ['role'] });\n },\n\n /**\n * Promise to fetch all users.\n * @return {Promise}\n */\n fetchAll(params) {\n const query = strapi.get('query-params').transform(USER_MODEL_UID, params ?? {});\n\n return strapi.db.query(USER_MODEL_UID).findMany(query);\n },\n\n /**\n * Promise to remove a/an user.\n * @return {Promise}\n */\n async remove(params) {\n // Invalidate sessions for all affected users\n const sessionManager = getSessionManager();\n if (sessionManager && sessionManager.hasOrigin('users-permissions') && params.id) {\n await sessionManager('users-permissions').invalidateRefreshToken(String(params.id));\n }\n\n return strapi.db.query(USER_MODEL_UID).delete({ where: params });\n },\n\n validatePassword(password, hash) {\n return bcrypt.compare(password, hash);\n },\n\n async sendConfirmationEmail(user) {\n const userPermissionService = getService('users-permissions');\n const pluginStore = await strapi.store({ type: 'plugin', name: 'users-permissions' });\n const userSchema = strapi.getModel(USER_MODEL_UID);\n\n const settings = await pluginStore\n .get({ key: 'email' })\n .then((storeEmail) => storeEmail.email_confirmation.options);\n\n // Sanitize the template's user information\n const sanitizedUserInfo = await sanitize.sanitizers.defaultSanitizeOutput(\n {\n schema: userSchema,\n getModel: strapi.getModel.bind(strapi),\n },\n user\n );\n\n const confirmationToken = crypto.randomBytes(20).toString('hex');\n\n await this.edit(user.id, { confirmationToken });\n\n const apiPrefix = strapi.config.get('api.rest.prefix');\n\n try {\n settings.message = await userPermissionService.template(settings.message, {\n URL: urlJoin(\n strapi.config.get('server.absoluteUrl'),\n apiPrefix,\n '/auth/email-confirmation'\n ),\n SERVER_URL: strapi.config.get('server.absoluteUrl'),\n ADMIN_URL: strapi.config.get('admin.absoluteUrl'),\n USER: sanitizedUserInfo,\n CODE: confirmationToken,\n });\n\n settings.object = await userPermissionService.template(settings.object, {\n USER: sanitizedUserInfo,\n });\n } catch {\n strapi.log.error(\n '[plugin::users-permissions.sendConfirmationEmail]: Failed to generate a template for \"user confirmation email\". Please make sure your email template is valid and does not contain invalid characters or patterns'\n );\n return;\n }\n\n // Send an email to the user.\n await strapi\n .plugin('email')\n .service('email')\n .send({\n to: user.email,\n from:\n settings.from.email && settings.from.name\n ? `${settings.from.name} <${settings.from.email}>`\n : undefined,\n replyTo: settings.response_email,\n subject: settings.object,\n text: settings.message,\n html: settings.message,\n });\n },\n});\n"],"names":["crypto","require$$0","bcrypt","require$$1","urlJoin","require$$2","sanitize","require$$3","toNumber","getOr","require$$4","getService","require$$5","USER_MODEL_UID","getSessionManager","manager","strapi","sessionManager","user","count","params","db","query","where","ensureHashedPasswords","values","attributes","getModel","key","type","rounds","hash","add","documents","create","data","populate","edit","userId","entry","findOne","id","select","update","documentId","fetch","get","transform","$and","fetchAuthenticatedUser","fetchAll","findMany","remove","hasOrigin","invalidateRefreshToken","String","delete","validatePassword","password","compare","sendConfirmationEmail","userPermissionService","pluginStore","store","name","userSchema","settings","then","storeEmail","email_confirmation","options","sanitizedUserInfo","sanitizers","defaultSanitizeOutput","schema","bind","confirmationToken","randomBytes","toString","apiPrefix","config","message","template","URL","SERVER_URL","ADMIN_URL","USER","CODE","object","log","error","plugin","service","send","to","email","from","undefined","replyTo","response_email","subject","text","html"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/plugin-users-permissions",
3
- "version": "5.47.1",
3
+ "version": "5.48.1",
4
4
  "description": "Protect your API with a full-authentication process based on JWT",
5
5
  "homepage": "https://strapi.io",
6
6
  "bugs": {
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "@strapi/design-system": "2.2.0",
57
57
  "@strapi/icons": "2.2.0",
58
- "@strapi/utils": "5.47.1",
58
+ "@strapi/utils": "5.48.1",
59
59
  "bcryptjs": "2.4.3",
60
60
  "formik": "2.4.5",
61
61
  "grant": "5.4.24",
@@ -75,9 +75,9 @@
75
75
  "zod": "3.25.67"
76
76
  },
77
77
  "devDependencies": {
78
- "@strapi/strapi": "5.47.1",
78
+ "@strapi/strapi": "5.48.1",
79
79
  "@testing-library/dom": "10.4.1",
80
- "@testing-library/react": "16.3.0",
80
+ "@testing-library/react": "16.3.2",
81
81
  "@testing-library/user-event": "14.6.1",
82
82
  "msw": "2.13.4",
83
83
  "react": "18.3.1",
@@ -93,7 +93,7 @@
93
93
  "styled-components": "^6.0.0"
94
94
  },
95
95
  "engines": {
96
- "node": ">=20.0.0 <=24.x.x",
96
+ "node": ">=20.0.0 <=26.x.x",
97
97
  "npm": ">=6.0.0"
98
98
  },
99
99
  "strapi": {
@@ -59,8 +59,12 @@ module.exports = ({ strapi }) => ({
59
59
  * @return {Promise}
60
60
  */
61
61
  async add(values) {
62
- return strapi.db.query(USER_MODEL_UID).create({
63
- data: await this.ensureHashedPasswords(values),
62
+ // Use the Document Service so relation inputs accept both the internal
63
+ // numeric id (legacy) and the documentId (v5 default) syntax, consistent
64
+ // with every other content-type endpoint. The Document Service hashes
65
+ // `password` attributes itself, so we must not pre-hash here.
66
+ return strapi.documents(USER_MODEL_UID).create({
67
+ data: values,
64
68
  populate: ['role'],
65
69
  });
66
70
  },
@@ -72,9 +76,22 @@ module.exports = ({ strapi }) => ({
72
76
  * @return {Promise}
73
77
  */
74
78
  async edit(userId, params = {}) {
75
- return strapi.db.query(USER_MODEL_UID).update({
76
- where: { id: userId },
77
- data: await this.ensureHashedPasswords(params),
79
+ // The user is addressed by its numeric id (e.g. the `/users/:id` route),
80
+ // but the Document Service updates by documentId. Resolve it first so the
81
+ // relation inputs are processed by the Document Service, which accepts both
82
+ // numeric ids (legacy) and documentIds (v5 default). The Document Service
83
+ // hashes `password` attributes itself, so we must not pre-hash here.
84
+ const entry = await strapi.db
85
+ .query(USER_MODEL_UID)
86
+ .findOne({ where: { id: userId }, select: ['documentId'] });
87
+
88
+ if (!entry) {
89
+ return null;
90
+ }
91
+
92
+ return strapi.documents(USER_MODEL_UID).update({
93
+ documentId: entry.documentId,
94
+ data: params,
78
95
  populate: ['role'],
79
96
  });
80
97
  },