supertokens-node
Version:
NodeJS driver for SuperTokens core
296 lines (295 loc) • 11.2 kB
JavaScript
;
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.userPut = void 0;
const error_1 = __importDefault(require("../../../../error"));
const utils_1 = require("../../utils");
const constants_1 = require("../../../emailpassword/constants");
const utils_2 = require("../../../passwordless/utils");
const recipeUserId_1 = __importDefault(require("../../../../recipeUserId"));
const updateEmailForRecipeId = async (stInstance, recipeId, recipeUserId, email, tenantId, userContext) => {
if (recipeId === "emailpassword") {
let emailFormFields = stInstance
.getRecipeInstanceOrThrow("emailpassword")
.config.signUpFeature.formFields.filter((field) => field.id === constants_1.FORM_FIELD_EMAIL_ID);
let validationError = await emailFormFields[0].validate(email, tenantId, userContext);
if (validationError !== undefined) {
return {
status: "INVALID_EMAIL_ERROR",
error: validationError,
};
}
const emailUpdateResponse = await stInstance
.getRecipeInstanceOrThrow("emailpassword")
.recipeInterfaceImpl.updateEmailOrPassword({
recipeUserId,
email,
userContext,
tenantIdForPasswordPolicy: tenantId,
});
if (emailUpdateResponse.status === "EMAIL_ALREADY_EXISTS_ERROR") {
return {
status: "EMAIL_ALREADY_EXISTS_ERROR",
};
} else if (emailUpdateResponse.status === "EMAIL_CHANGE_NOT_ALLOWED_ERROR") {
return {
status: "EMAIL_CHANGE_NOT_ALLOWED_ERROR",
reason: emailUpdateResponse.reason,
};
} else if (emailUpdateResponse.status === "UNKNOWN_USER_ID_ERROR") {
throw new Error("Should never come here");
}
return {
status: "OK",
};
}
if (recipeId === "passwordless") {
let isValidEmail = true;
let validationError = "";
const passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless");
const passwordlessConfig = passwordlessRecipe.config;
if (passwordlessConfig.contactMethod === "PHONE") {
const validationResult = await (0, utils_2.defaultValidateEmail)(email);
if (validationResult !== undefined) {
isValidEmail = false;
validationError = validationResult;
}
} else {
const validationResult = await passwordlessConfig.validateEmailAddress(email, tenantId);
if (validationResult !== undefined) {
isValidEmail = false;
validationError = validationResult;
}
}
if (!isValidEmail) {
return {
status: "INVALID_EMAIL_ERROR",
error: validationError,
};
}
const updateResult = await passwordlessRecipe.recipeInterfaceImpl.updateUser({
recipeUserId,
email,
userContext,
});
if (updateResult.status === "UNKNOWN_USER_ID_ERROR") {
throw new Error("Should never come here");
}
if (updateResult.status === "EMAIL_ALREADY_EXISTS_ERROR") {
return {
status: "EMAIL_ALREADY_EXISTS_ERROR",
};
}
if (
updateResult.status === "EMAIL_CHANGE_NOT_ALLOWED_ERROR" ||
updateResult.status === "PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR"
) {
return {
status: "EMAIL_CHANGE_NOT_ALLOWED_ERROR",
reason: updateResult.reason,
};
}
return {
status: "OK",
};
}
if (recipeId === "webauthn") {
const webauthnRecipe = stInstance.getRecipeInstanceOrThrow("webauthn");
let validationError = await webauthnRecipe.config.validateEmailAddress(email, tenantId, userContext);
if (validationError !== undefined) {
return {
status: "INVALID_EMAIL_ERROR",
error: validationError,
};
}
const emailUpdateResponse = await webauthnRecipe.recipeInterfaceImpl.updateUserEmail({
email,
recipeUserId: recipeUserId.getAsString(),
tenantId,
userContext,
});
if (emailUpdateResponse.status === "EMAIL_ALREADY_EXISTS_ERROR") {
return {
status: "EMAIL_ALREADY_EXISTS_ERROR",
};
} else if (emailUpdateResponse.status === "UNKNOWN_USER_ID_ERROR") {
throw new Error("Should never come here");
}
return {
status: "OK",
};
}
/**
* If it comes here then the user is a third party user in which case the UI should not have allowed this
*/
throw new Error("Should never come here");
};
const updatePhoneForRecipeId = async (stInstance, recipeUserId, phone, tenantId, userContext) => {
let isValidPhone = true;
let validationError = "";
const passwordlessRecipe = stInstance.getRecipeInstanceOrThrow("passwordless");
const passwordlessConfig = passwordlessRecipe.config;
if (passwordlessConfig.contactMethod === "EMAIL") {
const validationResult = await (0, utils_2.defaultValidatePhoneNumber)(phone);
if (validationResult !== undefined) {
isValidPhone = false;
validationError = validationResult;
}
} else {
const validationResult = await passwordlessConfig.validatePhoneNumber(phone, tenantId);
if (validationResult !== undefined) {
isValidPhone = false;
validationError = validationResult;
}
}
if (!isValidPhone) {
return {
status: "INVALID_PHONE_ERROR",
error: validationError,
};
}
const updateResult = await passwordlessRecipe.recipeInterfaceImpl.updateUser({
recipeUserId,
phoneNumber: phone,
userContext,
});
if (updateResult.status === "UNKNOWN_USER_ID_ERROR") {
throw new Error("Should never come here");
}
if (updateResult.status === "PHONE_NUMBER_ALREADY_EXISTS_ERROR") {
return {
status: "PHONE_ALREADY_EXISTS_ERROR",
};
}
if (updateResult.status === "PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR") {
return {
status: updateResult.status,
reason: updateResult.reason,
};
}
return {
status: "OK",
};
};
const userPut = async ({ stInstance, tenantId, options, userContext }) => {
const requestBody = await options.req.getJSONBody();
const recipeUserId = requestBody.recipeUserId;
const recipeId = requestBody.recipeId;
const firstName = requestBody.firstName;
const lastName = requestBody.lastName;
const email = requestBody.email;
const phone = requestBody.phone;
if (recipeUserId === undefined || typeof recipeUserId !== "string") {
throw new error_1.default({
message: "Required parameter 'recipeUserId' is missing or has an invalid type",
type: error_1.default.BAD_INPUT_ERROR,
});
}
if (recipeId === undefined || typeof recipeId !== "string") {
throw new error_1.default({
message: "Required parameter 'recipeId' is missing or has an invalid type",
type: error_1.default.BAD_INPUT_ERROR,
});
}
if (!(0, utils_1.isValidRecipeId)(recipeId)) {
throw new error_1.default({
message: "Invalid recipe id",
type: error_1.default.BAD_INPUT_ERROR,
});
}
if (firstName === undefined || typeof firstName !== "string") {
throw new error_1.default({
message: "Required parameter 'firstName' is missing or has an invalid type",
type: error_1.default.BAD_INPUT_ERROR,
});
}
if (lastName === undefined || typeof lastName !== "string") {
throw new error_1.default({
message: "Required parameter 'lastName' is missing or has an invalid type",
type: error_1.default.BAD_INPUT_ERROR,
});
}
if (email === undefined || typeof email !== "string") {
throw new error_1.default({
message: "Required parameter 'email' is missing or has an invalid type",
type: error_1.default.BAD_INPUT_ERROR,
});
}
if (phone === undefined || typeof phone !== "string") {
throw new error_1.default({
message: "Required parameter 'phone' is missing or has an invalid type",
type: error_1.default.BAD_INPUT_ERROR,
});
}
let userResponse = await (0, utils_1.getUserForRecipeId)(
stInstance,
new recipeUserId_1.default(recipeUserId),
recipeId,
userContext
);
if (userResponse.user === undefined || userResponse.recipe === undefined) {
throw new Error("Should never come here");
}
if (firstName.trim() !== "" || lastName.trim() !== "") {
let usermetadataRecipe = stInstance.getRecipeInstance("usermetadata");
if (usermetadataRecipe) {
let metaDataUpdate = {};
if (firstName.trim() !== "") {
metaDataUpdate["first_name"] = firstName.trim();
}
if (lastName.trim() !== "") {
metaDataUpdate["last_name"] = lastName.trim();
}
await usermetadataRecipe.recipeInterfaceImpl.updateUserMetadata({
userId: userResponse.user.id,
metadataUpdate: metaDataUpdate,
userContext,
});
}
}
if (email.trim() !== "") {
const emailUpdateResponse = await updateEmailForRecipeId(
stInstance,
userResponse.recipe,
new recipeUserId_1.default(recipeUserId),
email.trim(),
tenantId,
userContext
);
if (emailUpdateResponse.status === "EMAIL_CHANGE_NOT_ALLOWED_ERROR") {
return {
error: emailUpdateResponse.reason,
status: emailUpdateResponse.status,
};
}
if (emailUpdateResponse.status !== "OK") {
return emailUpdateResponse;
}
}
if (phone.trim() !== "") {
const phoneUpdateResponse = await updatePhoneForRecipeId(
stInstance,
new recipeUserId_1.default(recipeUserId),
phone.trim(),
tenantId,
userContext
);
if (phoneUpdateResponse.status === "PHONE_NUMBER_CHANGE_NOT_ALLOWED_ERROR") {
return {
error: phoneUpdateResponse.reason,
status: phoneUpdateResponse.status,
};
}
if (phoneUpdateResponse.status !== "OK") {
return phoneUpdateResponse;
}
}
return {
status: "OK",
};
};
exports.userPut = userPut;