/* This file is part of »zeitbild«. Copyright 2025 'kcf' »zeitbild« is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. »zeitbild« is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with »zeitbild«. If not, see . */ namespace _zeitbild.api { /** */ function get_group_name( group_name_raw : string ) : string { return lib_plankton.string.coin( "auto-{{name_raw}}", { "name_raw": group_name_raw, } ); } /** */ function get_group_label( group_name_raw : string ) : string { return lib_plankton.string.coin( "{{name_raw}}", { "name_raw": group_name_raw, } ); } /** */ export function register_session_oidc( rest_subject : lib_plankton.rest_http.type_rest ) : void { register< null, string >( rest_subject, lib_plankton.http.enum_method.get, "/session/oidc", { "description": "verarbeitet einen OIDC login callback", "query_parameters": () => ([ { "name": "code", "required": true, "description": null, }, { "name": "iss", "required": true, "description": null, }, { "name": "scope", "required": true, "description": null, }, { "name": "state", "required": true, "description": null, }, ]), "input_schema": () => ({ "type": "null", }), "output_schema": () => ({ "nullable": false, "type": "string", }), "response_body_mimetype": "text/html", "response_body_encode": (output => Buffer.from(output)), "restriction": restriction_none, "execution": async (stuff) => { const data : { token : string; userinfo : { name : (null | string); email : (null | string); groups : (null | Array); }; redirect_uri_template : string; } = await _zeitbild.auth.oidc_handle_authorization_callback( (stuff.headers["Cookie"] ?? stuff.headers["cookie"] ?? null), stuff.query_parameters ); if (data.userinfo.name === null) { return Promise.reject( new Error( "IDP did not return user name" ) ); } else { // groups const group_ids : Array<_zeitbild.type_group_id> = await Promise.all<_zeitbild.type_group_id>( (data.userinfo.groups ?? []) .map( async (group_name_raw) => { const group_name : string = get_group_name(group_name_raw); const group_id_raw : (null | _zeitbild.type_group_id) = await ( _zeitbild.repository.group.identify(group_name) .catch(() => Promise.resolve(null)) ); if (group_id_raw === null) { const group_id : _zeitbild.type_group_id = await _zeitbild.service.group.add( { "name": group_name, "label": get_group_label(group_name_raw), } ); return group_id; } else { const group_id : _zeitbild.type_group_id = group_id_raw; await _zeitbild.service.group.change( group_id, { "name": group_name, "label": get_group_label(group_name_raw), } ); return group_id; } } ) ); const user_id : _zeitbild.type_user_id = await (async () => { const user_object : _zeitbild.type_user_object = { "name": (data.userinfo.name as string), "groups": group_ids, "email_address": data.userinfo.email, "dav_token": null, }; const user_id_raw : (null | _zeitbild.type_user_id) = await ( _zeitbild.service.user.identify(data.userinfo.name as string) .catch(() => Promise.resolve(null)) ); if (user_id_raw === null) { // provision const user_id : _zeitbild.type_user_id = await _zeitbild.service.user.add( user_object ); lib_plankton.log.info( "user_provisioned", { "id": user_id, "name": user_object.name, } ); return user_id; } else { const user_id : _zeitbild.type_user_id = user_id_raw; // update await _zeitbild.service.user.change( user_id, user_object ); lib_plankton.log.info( "user_updated", { "id": user_id, "name": user_object.name, } ); return user_id; } }) (); const session_key : string = await lib_plankton.session.begin( data.userinfo.name, { "data": { "oidc_token": data.token, } } ); return Promise.resolve( { "status_code": 200, "data": lib_plankton.string.coin( "", { "url": lib_plankton.string.coin( data.redirect_uri_template, { "session_key": session_key, } ), } ), } ); } }, } ); } }