const { OIDCIdentity, User } = require('../../models'); async function getUserIdentities(userId) { return await OIDCIdentity.findAll({ where: { user_id: userId }, order: [['created_at', 'DESC']], attributes: [ 'id', 'provider_slug', 'email', 'name', 'picture', 'first_login_at', 'last_login_at', 'created_at', ], }); } async function getIdentityById(identityId) { return await OIDCIdentity.findByPk(identityId, { include: [ { model: User, as: 'User', attributes: ['id', 'email', 'username', 'is_admin'], }, ], }); } async function unlinkIdentity(identityId, userId) { const identity = await OIDCIdentity.findOne({ where: { id: identityId, user_id: userId, }, }); if (!identity) { throw new Error('Identity not found or does not belong to this user'); } const user = await User.findByPk(userId); const hasPassword = !!user.password_digest; const otherIdentities = await OIDCIdentity.count({ where: { user_id: userId, id: { [require('sequelize').Op.ne]: identityId }, }, }); if (!hasPassword && otherIdentities === 0) { throw new Error( 'Cannot unlink the last authentication method. Please set a password first or link another provider.' ); } await identity.destroy(); return true; } async function canUnlink(identityId, userId) { const identity = await OIDCIdentity.findOne({ where: { id: identityId, user_id: userId, }, }); if (!identity) { return { canUnlink: false, reason: 'Identity not found' }; } const user = await User.findByPk(userId); const hasPassword = !!user.password_digest; const otherIdentities = await OIDCIdentity.count({ where: { user_id: userId, id: { [require('sequelize').Op.ne]: identityId }, }, }); if (!hasPassword && otherIdentities === 0) { return { canUnlink: false, reason: 'This is your only authentication method', }; } return { canUnlink: true }; } async function updateIdentityClaims(identityId, claims) { const identity = await OIDCIdentity.findByPk(identityId); if (!identity) { throw new Error('Identity not found'); } await identity.update({ email: claims.email || identity.email, name: claims.name || identity.name, given_name: claims.given_name || identity.given_name, family_name: claims.family_name || identity.family_name, picture: claims.picture || identity.picture, raw_claims: claims, last_login_at: new Date(), }); return identity; } module.exports = { getUserIdentities, getIdentityById, unlinkIdentity, canUnlink, updateIdentityClaims, };