const passport = require('passport'); const { Issuer, Strategy: OpenIDStrategy } = require('openid-client'); const axios = require('axios'); const fs = require('fs'); const path = require('path'); const config = require('../../config/loader'); const domains = config.domains; const User = require('../models/User'); let crypto; try { crypto = require('node:crypto'); } catch (err) { console.error('crypto support is disabled!'); } const downloadImage = async (url, imagePath, accessToken) => { try { const response = await axios.get(url, { headers: { Authorization: `Bearer ${accessToken}`, }, responseType: 'arraybuffer', }); fs.mkdirSync(path.dirname(imagePath), { recursive: true }); fs.writeFileSync(imagePath, response.data); const fileName = path.basename(imagePath); return `/images/openid/${fileName}`; } catch (error) { console.error(`Error downloading image at URL "${url}": ${error}`); return ''; } }; async function setupOpenId() { try { const issuer = await Issuer.discover(process.env.OPENID_ISSUER); const client = new issuer.Client({ client_id: process.env.OPENID_CLIENT_ID, client_secret: process.env.OPENID_CLIENT_SECRET, redirect_uris: [domains.server + process.env.OPENID_CALLBACK_URL], }); const openidLogin = new OpenIDStrategy( { client, params: { scope: process.env.OPENID_SCOPE, }, }, async (tokenset, userinfo, done) => { try { let user = await User.findOne({ openidId: userinfo.sub }); if (!user) { user = await User.findOne({ email: userinfo.email }); } let fullName = ''; if (userinfo.given_name && userinfo.family_name) { fullName = userinfo.given_name + ' ' + userinfo.family_name; } else if (userinfo.given_name) { fullName = userinfo.given_name; } else if (userinfo.family_name) { fullName = userinfo.family_name; } else { fullName = userinfo.username || userinfo.email; } if (!user) { user = new User({ provider: 'openid', openidId: userinfo.sub, username: userinfo.username || userinfo.given_name || '', email: userinfo.email || '', emailVerified: userinfo.email_verified || false, name: fullName, }); } else { user.provider = 'openid'; user.openidId = userinfo.sub; user.username = userinfo.given_name || ''; user.name = fullName; } if (userinfo.picture) { const imageUrl = userinfo.picture; let fileName; if (crypto) { const hash = crypto.createHash('sha256'); hash.update(userinfo.sub); fileName = hash.digest('hex') + '.png'; } else { fileName = userinfo.sub + '.png'; } const imagePath = path.join( __dirname, '..', '..', 'client', 'public', 'images', 'openid', fileName, ); const imagePathOrEmpty = await downloadImage( imageUrl, imagePath, tokenset.access_token, ); user.avatar = imagePathOrEmpty; } else { user.avatar = ''; } await user.save(); done(null, user); } catch (err) { done(err); } }, ); passport.use('openid', openidLogin); } catch (err) { console.error(err); } } module.exports = setupOpenId;