Skip to content

Commit

Permalink
login-account-proxy: Better handle duplicate email change requests
Browse files Browse the repository at this point in the history
  • Loading branch information
domdomegg committed Oct 16, 2024
1 parent 0b6021e commit d1dfa58
Showing 1 changed file with 34 additions and 13 deletions.
47 changes: 34 additions & 13 deletions apps/login-account-proxy/src/pages/api/public/submit.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import axios from 'axios';
import createHttpError from 'http-errors';
import { apiRoute } from '../../../lib/api/apiRoute';
import env from '../../../lib/api/env';
import { slackAlert } from '../../../lib/api/slackAlert';

export type SubmitRequest = {
oldEmail: string,
oldEmail?: string,
newEmail: string,
password: string,
secret: string,
Expand Down Expand Up @@ -43,6 +45,8 @@ export default apiRoute(async (
return;
}

const isChangingEmail = data.oldEmail && data.oldEmail !== data.newEmail;

const clientCredentialsGrantParams = new URLSearchParams();
clientCredentialsGrantParams.append('grant_type', 'client_credentials');
clientCredentialsGrantParams.append('client_id', 'login-account-proxy');
Expand All @@ -56,24 +60,25 @@ export default apiRoute(async (
const potentialUsers = (await axios.get<{ id: string, email: string }[]>(`https://login.bluedot.org/admin/realms/customers/users?email=${encodeURIComponent(data.oldEmail || data.newEmail)}&exact=true`, { headers })).data;

if (potentialUsers.length > 1) {
throw new Error(`Found more than one user for email: ${data.newEmail}`);
throw new Error(`Found more than one user for email: ${data.oldEmail || data.newEmail}`);
}

if (potentialUsers.length === 1) {
if (data.oldEmail && data.oldEmail !== data.newEmail) {
await axios.put(`https://login.bluedot.org/admin/realms/customers/users/${potentialUsers[0]!.id}`, {
...potentialUsers[0],
email: data.newEmail,
username: data.newEmail,
}, { headers });
// No account exists, and we expect one to
if (isChangingEmail && potentialUsers.length === 0) {
const potentialNewUsers = (await axios.get<{ id: string, email: string }[]>(`https://login.bluedot.org/admin/realms/customers/users?email=${encodeURIComponent(data.newEmail)}&exact=true`, { headers })).data;

if (potentialNewUsers.length === 0) {
throw new createHttpError.BadRequest(`Tried to change email, but cannot find existing accounts in Keycloak for email ${data.oldEmail} or ${data.newEmail}`);
}

await axios.put(`https://login.bluedot.org/admin/realms/customers/users/${potentialUsers[0]!.id}/reset-password`, {
type: 'password',
value: data.password,
}, { headers });
if (potentialNewUsers.length >= 1) {
slackAlert([`User tried to change email from ${data.oldEmail} to ${data.newEmail}, but only found account for new email. Ignoring this request, because this usually indicates it previously succeeded and they clicked the button in Bubble twice in quick succession.`]);
res.status(200).json({ type: 'success' });
return;
}
}

// No account exists, and we don't expect one to
if (potentialUsers.length === 0) {
await axios.post('https://login.bluedot.org/admin/realms/customers/users', {
enabled: true,
Expand All @@ -85,5 +90,21 @@ export default apiRoute(async (
}, { headers });
}

// An account exists
if (potentialUsers.length === 1) {
if (isChangingEmail) {
await axios.put(`https://login.bluedot.org/admin/realms/customers/users/${potentialUsers[0]!.id}`, {
...potentialUsers[0],
email: data.newEmail,
username: data.newEmail,
}, { headers });
}

await axios.put(`https://login.bluedot.org/admin/realms/customers/users/${potentialUsers[0]!.id}/reset-password`, {
type: 'password',
value: data.password,
}, { headers });
}

res.status(200).json({ type: 'success' });
}, 'insecure_no_auth');

0 comments on commit d1dfa58

Please sign in to comment.