From d0d28cb445fca3b6c318bf34a0dfe8e7497c38e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Mon, 20 May 2024 14:06:54 +0200 Subject: [PATCH] [mod] password change: Anpassungen --- .../actions/member_password_change_execute.ts | 60 +++++++++++--- source/services/member.ts | 81 +++++++++++-------- 2 files changed, 98 insertions(+), 43 deletions(-) diff --git a/source/api/actions/member_password_change_execute.ts b/source/api/actions/member_password_change_execute.ts index 2e699f0..48c0d17 100644 --- a/source/api/actions/member_password_change_execute.ts +++ b/source/api/actions/member_password_change_execute.ts @@ -13,7 +13,12 @@ namespace _espe.api token : string; password_new : string; }, - null + Array< + { + incident : string; + details : Record; + } + > >( rest_subject, lib_plankton.http.enum_method.patch, @@ -41,20 +46,53 @@ namespace _espe.api ] }), "output_schema": () => ({ - "nullable": true + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "object", + "properties": { + "incident": { + "nullable": false, + "type": "string" + }, + "details": { + "nullable": false, + "type": "object", + "properties": {}, + "additionalProperties": { + "nullable": true + }, + "required": [] + }, + }, + "additionalProperties": false, + "required": [ + "incident", + "details", + ] + } }), "restriction": restriction_none, - "execution": async ({"path_parameters": path_parameters, "input": input}) => { + "execution": ({"path_parameters": path_parameters, "input": input}) => { const member_id : _espe.type.member_id = parseInt(path_parameters["id"]); - await _espe.service.member.password_change_execute( - member_id, - input.token, - input.password_new + return ( + _espe.service.member.password_change_execute( + member_id, + input.token, + input.password_new + ) + .then( + flaws => Promise.resolve({ + "status_code": ( + (flaws.length <= 0) + ? 200 + : 409 + ), + "data": flaws + }) + ) ); - return Promise.resolve({ - "status_code": 200, - "data": null - }); }, } ) diff --git a/source/services/member.ts b/source/services/member.ts index 81d7b53..fc85a4e 100644 --- a/source/services/member.ts +++ b/source/services/member.ts @@ -573,7 +573,8 @@ namespace _espe.service.member }; await _espe.repository.member.update(member_id, member_object_new); // notify_change(); - await _espe.helpers.email_send( + // do NOT wait in order to reduce information for potential attackers + /*await*/ _espe.helpers.email_send( [ member_object_old.email_address_private, ], @@ -581,7 +582,7 @@ namespace _espe.service.member lib_plankton.string.coin( _espe.conf.get().settings.password_change.initialization_email.body, { - "name": member_object_old.name_real_value, + "name": name_display(member_object_old), "url": lib_plankton.string.coin( "{{base}}{{rest}}", { @@ -614,10 +615,15 @@ namespace _espe.service.member member_id : _espe.type.member_id, token : string, password_new : string - ) : Promise + ) : Promise;}>> { const member_object_old : _espe.type.member_object = await _espe.repository.member.read(member_id); - if (! (token === member_object_old.password_change_token)) { + let flaws : Array<{incident : string; details : Record;}> = []; + if ( + (member_object_old.password_change_token === null) + || + (! (token === member_object_old.password_change_token)) + ) { lib_plankton.log.notice( "member_password_change_token_invalid", { @@ -625,38 +631,49 @@ namespace _espe.service.member "token_sent": token, } ); - throw (new Error("password change token is invalid")); + flaws.push({"incident": "token_invalid", "details": {}}); } else { - const member_object_new : _espe.type.member_object = { - "membership_number": member_object_old.membership_number, - "name_real_value": member_object_old.name_real_value, - "name_real_index": member_object_old.name_real_index, - "email_address_private": member_object_old.email_address_private, - "registered": member_object_old.registered, - "enabled": member_object_old.enabled, - "email_use_veiled_address": member_object_old.email_use_veiled_address, - "email_use_nominal_address": member_object_old.email_use_nominal_address, - "email_redirect_to_private_address": member_object_old.email_redirect_to_private_address, - "email_allow_sending": member_object_old.email_allow_sending, - "password_image": await password_image(password_new), - "password_change_last_attempt": member_object_old.password_change_last_attempt, - "password_change_token": null, - }; - await _espe.repository.member.update(member_id, member_object_new); - notify_change(); - await _espe.helpers.email_send( - [ - member_object_old.email_address_private, - ], - _espe.conf.get().settings.password_change.execution_email.subject, - lib_plankton.string.coin( - _espe.conf.get().settings.password_change.execution_email.body, - { - } - ) + flaws = flaws.concat( + validate_password(password_new) + .map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details})) ); + if (flaws.length > 0) { + // do nothing + } + else { + const member_object_new : _espe.type.member_object = { + "membership_number": member_object_old.membership_number, + "name_real_value": member_object_old.name_real_value, + "name_real_index": member_object_old.name_real_index, + "email_address_private": member_object_old.email_address_private, + "registered": member_object_old.registered, + "enabled": member_object_old.enabled, + "email_use_veiled_address": member_object_old.email_use_veiled_address, + "email_use_nominal_address": member_object_old.email_use_nominal_address, + "email_redirect_to_private_address": member_object_old.email_redirect_to_private_address, + "email_allow_sending": member_object_old.email_allow_sending, + "password_image": await password_image(password_new), + "password_change_last_attempt": member_object_old.password_change_last_attempt, + "password_change_token": null, + }; + await _espe.repository.member.update(member_id, member_object_new); + notify_change(); + await _espe.helpers.email_send( + [ + member_object_old.email_address_private, + ], + _espe.conf.get().settings.password_change.execution_email.subject, + lib_plankton.string.coin( + _espe.conf.get().settings.password_change.execution_email.body, + { + "name": name_display(member_object_old), + } + ) + ); + } } + return flaws; }