diff --git a/source/api/actions/member_register.ts b/source/api/actions/member_register.ts index a03b1d8..afe3055 100644 --- a/source/api/actions/member_register.ts +++ b/source/api/actions/member_register.ts @@ -15,7 +15,12 @@ namespace _espe.api email_redirect_to_private_address : boolean; password : (null | string); }, - null + Array< + { + incident : string; + details : Record; + } + > >( rest_subject, lib_plankton.http.enum_method.post, @@ -65,7 +70,7 @@ namespace _espe.api stuff => parseInt(stuff.path_parameters["id"]), stuff => stuff.query_parameters["key"] ), - "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"]); return ( _espe.service.member.register( @@ -78,15 +83,13 @@ namespace _espe.api } ) .then( - () => Promise.resolve({ - "status_code": 200, - "data": null, - }) - ) - .catch( - () => Promise.resolve({ - "status_code": 409, - "data": /*"bereits registriert"*/null, + flaws => Promise.resolve({ + "status_code": ( + (flaws.length <= 0) + ? 200 + : 409 + ), + "data": flaws }) ) ); diff --git a/source/services/member.ts b/source/services/member.ts index 5cf0570..605de49 100644 --- a/source/services/member.ts +++ b/source/services/member.ts @@ -29,6 +29,78 @@ namespace _espe.service.member } + /** + * @todo test + */ + function validate_password( + password : string + ) : Array<{incident : string; details : Record}> + { + let flaws : Array<{incident : string; details : Record}> = []; + + const conf = { + "minimum_length": 8, + "maximum_length": 240, + // "pattern": + "must_contain_letter": true, + "must_contain_number": true, + "must_contain_special_character": true, + }; + + if (password.length < conf.minimum_length) { + flaws.push( + { + "incident": "too_short", + "details": { + "minimum_length": conf.minimum_length, + "actual_length": password.length, + } + } + ); + } + if (password.length > conf.maximum_length) { + flaws.push( + { + "incident": "too_long", + "details": { + "maximum_length": conf.maximum_length, + "actual_length": password.length, + } + } + ); + } + if (conf.must_contain_letter && (! (new RegExp("[a-zA-Z]")).test(password))) { + flaws.push( + { + "incident": "lacks_letter", + "details": { + } + } + ); + } + if (conf.must_contain_number && (! (new RegExp("[0-9]")).test(password))) { + flaws.push( + { + "incident": "lacks_number", + "details": { + } + } + ); + } + if (conf.must_contain_special_character && (! (new RegExp("[!?-_.,;/\~%&$'()\\[\\]{}^'#|+*<>=\"`:@]")).test(password))) { + flaws.push( + { + "incident": "lacks_special_character", + "details": { + } + } + ); + } + + return flaws; + } + + /** */ export function name_login( @@ -38,7 +110,17 @@ namespace _espe.service.member return lib_plankton.string.coin( "{{object}}{{extension}}", { - "object": object.name_real_value.toLowerCase().replace(new RegExp(" ", "g"), "."), + "object": lib_plankton.call.convey( + object.name_real_value, + [ + x => x.toLowerCase(), + x => x.replace(new RegExp(" ", "g"), "."), + x => x.replace(new RegExp("ä", "g"), "ae"), + x => x.replace(new RegExp("ö", "g"), "oe"), + x => x.replace(new RegExp("ü", "g"), "ue"), + x => x.replace(new RegExp("ß", "g"), "ss"), + ] + ), "extension": ( (object.name_real_index <= 1) ? "" @@ -267,7 +349,7 @@ namespace _espe.service.member options : { notify_admins ?: boolean; } = {} - ) : Promise + ) : Promise;}>> { options = Object.assign( { @@ -275,31 +357,59 @@ namespace _espe.service.member }, options ); + const member_object : _espe.type.member_object = await get(member_id); + let flaws : Array<{incident : string; details : Record;}> = []; + const password_set : boolean = ( + (data.password !== null) + && + (data.password !== "") + ); if (member_object.registered) { - return Promise.reject(new Error("already registered")); + flaws.push({"incident": "already_registered", "details": {}}); + } + else { + if (password_set) { + flaws = flaws.concat( + validate_password(data.password) + .map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details})) + ); + } + else { + // do nothing + } + } + + if (flaws.length > 0) { + // do nothing } else { member_object.email_use_veiled_address = data.email_use_veiled_address member_object.email_use_nominal_address = data.email_use_nominal_address member_object.email_redirect_to_private_address = data.email_redirect_to_private_address; - member_object.password_image = await _espe.helpers.bcrypt_compute(data.password); + member_object.password_image = ( + password_set + ? await _espe.helpers.bcrypt_compute(data.password) + : null + ); member_object.registered = true; await _espe.repository.member.update(member_id, member_object); + + notify_change(); + + if (! options.notify_admins) { + // do nothing + } + else { + await _espe.helpers.email_send( + _espe.conf.get().admins.map(admin => admin.email_address).filter(x => (x !== null)), + "Eingegangene Registrierung", + ("Member-ID: " + member_id.toFixed(0)) + ); + } } - notify_change(); - - if (! options.notify_admins) { - // do nothing - } - else { - await _espe.helpers.email_send( - _espe.conf.get().admins.map(admin => admin.email_address).filter(x => (x !== null)), - "Eingegangene Registrierung", - ("Member-ID: " + member_id.toFixed(0)) - ); - } + return Promise.resolve(flaws); }