Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recipe interface changes regarding account-linking #439

Merged
merged 15 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions lib/build/recipe/accountlinking/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ export declare type RecipeInterface = {
}
| {
status:
| "PRIMARY_USER_ALREADY_EXISTS_FOR_RECIPE_USER_ID_ERROR"
| "PRIMARY_USER_ALREADY_EXISTS_FOR_ACCOUNT_INFO_ERROR";
| "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
| "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
>;
createPrimaryUser: (input: {
Expand All @@ -78,9 +79,10 @@ export declare type RecipeInterface = {
}
| {
status:
| "PRIMARY_USER_ALREADY_EXISTS_FOR_RECIPE_USER_ID_ERROR"
| "PRIMARY_USER_ALREADY_EXISTS_FOR_ACCOUNT_INFO_ERROR";
| "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR"
| "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
>;
canLinkAccounts: (input: {
Expand All @@ -93,14 +95,17 @@ export declare type RecipeInterface = {
}
| {
status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
description: string;
primaryUserId: string;
}
| {
status: "ACCOUNTS_ALREADY_LINKED_ERROR";
description: string;
}
| {
status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
>;
linkAccounts: (input: {
Expand All @@ -114,13 +119,16 @@ export declare type RecipeInterface = {
| {
status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
| {
status: "ACCOUNTS_ALREADY_LINKED_ERROR";
description: string;
}
| {
status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
>;
unlinkAccounts: (input: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ declare type Response =
| {
status: "OK";
}
| {
status: "PROVIDE_RECIPE_USER_ID_AS_USER_ID_ERROR";
}
| {
status: "INVALID_PASSWORD_ERROR";
error: string;
Expand Down
5 changes: 3 additions & 2 deletions lib/build/recipe/dashboard/api/userdetails/userPasswordPut.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ exports.userPasswordPut = (_, options) =>
__awaiter(void 0, void 0, void 0, function* () {
const requestBody = yield options.req.getJSONBody();
const userId = requestBody.userId;
const email = requestBody.email;
const newPassword = requestBody.newPassword;
if (userId === undefined || typeof userId !== "string") {
throw new error_1.default({
Expand Down Expand Up @@ -80,7 +81,7 @@ exports.userPasswordPut = (_, options) =>
error: passwordValidationError,
};
}
const passwordResetToken = yield emailpassword_1.default.createResetPasswordToken(userId);
const passwordResetToken = yield emailpassword_1.default.createResetPasswordToken(userId, email);
if (passwordResetToken.status === "UNKNOWN_USER_ID_ERROR") {
// Techincally it can but its an edge case so we assume that it wont
throw new Error("Should never come here");
Expand All @@ -106,7 +107,7 @@ exports.userPasswordPut = (_, options) =>
error: passwordValidationError,
};
}
const passwordResetToken = yield thirdpartyemailpassword_1.default.createResetPasswordToken(userId);
const passwordResetToken = yield thirdpartyemailpassword_1.default.createResetPasswordToken(userId, email);
if (passwordResetToken.status === "UNKNOWN_USER_ID_ERROR") {
// Techincally it can but its an edge case so we assume that it wont
throw new Error("Should never come here");
Expand Down
14 changes: 13 additions & 1 deletion lib/build/recipe/emailpassword/api/implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ const logger_1 = require("../../../logger");
const session_1 = require("../../session");
function getAPIImplementation() {
return {
linkAccountToExistingAccountPOST: function (_input) {
return __awaiter(this, void 0, void 0, function* () {
return {
status: "ACCOUNT_NOT_VERIFIED_ERROR",
isNotVerifiedAccountFromInputSession: false,
description: "",
};
});
},
emailExistsGET: function ({ email, options, userContext }) {
return __awaiter(this, void 0, void 0, function* () {
let user = yield options.recipeImplementation.getUserByEmail({ email, userContext });
Expand All @@ -54,7 +63,8 @@ function getAPIImplementation() {
};
}
let response = yield options.recipeImplementation.createResetPasswordToken({
userId: user.id,
userId: user.recipeUserId,
email: user.email,
userContext,
});
if (response.status === "UNKNOWN_USER_ID_ERROR") {
Expand Down Expand Up @@ -138,6 +148,8 @@ function getAPIImplementation() {
status: "OK",
session,
user,
createdNewUser: true,
createdNewRecipeUser: true,
};
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class BackwardCompatibilityService {
this.sendEmail = (input) =>
__awaiter(this, void 0, void 0, function* () {
let user = yield this.recipeInterfaceImpl.getUserById({
userId: input.user.id,
userId: input.user.recipeUserId,
userContext: input.userContext,
});
if (user === undefined) {
Expand Down
15 changes: 14 additions & 1 deletion lib/build/recipe/emailpassword/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,20 @@ export default class Wrapper {
>;
static getUserById(userId: string, userContext?: any): Promise<User | undefined>;
static getUserByEmail(email: string, userContext?: any): Promise<User | undefined>;
/**
* We do not make email optional here cause we want to
* allow passing in primaryUserId. If we make email optional,
* and if the user provides a primaryUserId, then it may result in two problems:
* - there is no recipeUserId = input primaryUserId, in this case,
* this function will throw an error
* - There is a recipe userId = input primaryUserId, but that recipe has no email,
* or has wrong email compared to what the user wanted to generate a reset token for.
*
* And we want to allow primaryUserId being passed in.
*/
static createResetPasswordToken(
userId: string,
email: string,
userContext?: any
): Promise<
| {
Expand All @@ -52,7 +64,8 @@ export default class Wrapper {
): Promise<
| {
status: "OK";
userId?: string | undefined;
email: string;
userId: string;
}
| {
status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
Expand Down
14 changes: 13 additions & 1 deletion lib/build/recipe/emailpassword/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,21 @@ class Wrapper {
userContext: userContext === undefined ? {} : userContext,
});
}
static createResetPasswordToken(userId, userContext) {
/**
* We do not make email optional here cause we want to
* allow passing in primaryUserId. If we make email optional,
* and if the user provides a primaryUserId, then it may result in two problems:
* - there is no recipeUserId = input primaryUserId, in this case,
* this function will throw an error
* - There is a recipe userId = input primaryUserId, but that recipe has no email,
* or has wrong email compared to what the user wanted to generate a reset token for.
*
* And we want to allow primaryUserId being passed in.
*/
static createResetPasswordToken(userId, email, userContext) {
return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.createResetPasswordToken({
userId,
email,
userContext: userContext === undefined ? {} : userContext,
});
}
Expand Down
71 changes: 65 additions & 6 deletions lib/build/recipe/emailpassword/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,20 @@ export declare type RecipeInterface = {
>;
getUserById(input: { userId: string; userContext: any }): Promise<User | undefined>;
getUserByEmail(input: { email: string; userContext: any }): Promise<User | undefined>;
/**
* We do not make email optional here cause we want to
* allow passing in primaryUserId. If we make email optional,
* and if the user provides a primaryUserId, then it may result in two problems:
* - there is no recipeUserId = input primaryUserId, in this case,
* this function will throw an error
* - There is a recipe userId = input primaryUserId, but that recipe has no email,
* or has wrong email compared to what the user wanted to generate a reset token for.
*
* And we want to allow primaryUserId being passed in.
*/
createResetPasswordToken(input: {
userId: string;
email: string;
userContext: any;
}): Promise<
| {
Expand All @@ -123,11 +135,8 @@ export declare type RecipeInterface = {
}): Promise<
| {
status: "OK";
/**
* The id of the user whose password was reset.
* Defined for Core versions 3.9 or later
*/
userId?: string;
email: string;
userId: string;
}
| {
status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
Expand Down Expand Up @@ -179,6 +188,10 @@ export declare type APIInterface = {
| {
status: "OK";
}
| {
status: "PASSWORD_RESET_NOT_ALLOWED";
reason: string;
}
| GeneralErrorResponse
>);
passwordResetPOST:
Expand All @@ -194,7 +207,8 @@ export declare type APIInterface = {
}) => Promise<
| {
status: "OK";
userId?: string;
email: string;
userId: string;
}
| {
status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
Expand Down Expand Up @@ -234,18 +248,63 @@ export declare type APIInterface = {
| {
status: "OK";
user: User;
createdNewUser: boolean;
session: SessionContainerInterface;
}
| {
status: "EMAIL_ALREADY_EXISTS_ERROR";
}
| {
status: "SIGNUP_NOT_ALLOWED";
reason: string;
}
| GeneralErrorResponse
>);
linkAccountToExistingAccountPOST:
| undefined
| ((input: {
formFields: {
id: string;
value: string;
}[];
session: SessionContainerInterface;
options: APIOptions;
userContext: any;
}) => Promise<
| {
status: "OK";
user: User;
createdNewRecipeUser: boolean;
session: SessionContainerInterface;
wereAccountsAlreadyLinked: boolean;
}
| {
status: "RECIPE_USER_ID_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
| {
status: "ACCOUNT_INFO_ALREADY_LINKED_WITH_ANOTHER_PRIMARY_USER_ID_ERROR";
primaryUserId: string;
description: string;
}
| {
status: "ACCOUNT_LINKING_NOT_ALLOWED_ERROR";
description: string;
}
| {
status: "ACCOUNT_NOT_VERIFIED_ERROR";
isNotVerifiedAccountFromInputSession: boolean;
description: string;
}
| GeneralErrorResponse
>);
};
export declare type TypeEmailPasswordPasswordResetEmailDeliveryInput = {
type: "PASSWORD_RESET";
user: {
id: string;
recipeUserId: string;
email: string;
};
passwordResetLink: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function getIterfaceImpl(apiImplmentation) {
var _a, _b, _c, _d, _e;
var _a, _b, _c, _d, _e, _f;
return {
emailExistsGET:
(_a = apiImplmentation.emailPasswordEmailExistsGET) === null || _a === void 0
Expand All @@ -21,6 +21,10 @@ function getIterfaceImpl(apiImplmentation) {
(_e = apiImplmentation.emailPasswordSignUpPOST) === null || _e === void 0
? void 0
: _e.bind(apiImplmentation),
linkAccountToExistingAccountPOST:
(_f = apiImplmentation.linkEmailPasswordAccountToExistingAccountPOST) === null || _f === void 0
? void 0
: _f.bind(apiImplmentation),
};
}
exports.default = getIterfaceImpl;
18 changes: 11 additions & 7 deletions lib/build/recipe/thirdpartyemailpassword/api/implementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const implementation_2 = require("../../thirdparty/api/implementation");
const emailPasswordAPIImplementation_1 = require("./emailPasswordAPIImplementation");
const thirdPartyAPIImplementation_1 = require("./thirdPartyAPIImplementation");
function getAPIImplementation() {
var _a, _b, _c, _d, _e, _f, _g, _h;
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
let emailPasswordImplementation = implementation_1.default();
let thirdPartyImplementation = implementation_2.default();
return {
Expand All @@ -29,18 +29,22 @@ function getAPIImplementation() {
(_e = emailPasswordImplementation.generatePasswordResetTokenPOST) === null || _e === void 0
? void 0
: _e.bind(emailPasswordAPIImplementation_1.default(this)),
passwordResetPOST:
(_f = emailPasswordImplementation.passwordResetPOST) === null || _f === void 0
linkEmailPasswordAccountToExistingAccountPOST:
(_f = emailPasswordImplementation.linkAccountToExistingAccountPOST) === null || _f === void 0
? void 0
: _f.bind(emailPasswordAPIImplementation_1.default(this)),
passwordResetPOST:
(_g = emailPasswordImplementation.passwordResetPOST) === null || _g === void 0
? void 0
: _g.bind(emailPasswordAPIImplementation_1.default(this)),
thirdPartySignInUpPOST:
(_g = thirdPartyImplementation.signInUpPOST) === null || _g === void 0
(_h = thirdPartyImplementation.signInUpPOST) === null || _h === void 0
? void 0
: _g.bind(thirdPartyAPIImplementation_1.default(this)),
: _h.bind(thirdPartyAPIImplementation_1.default(this)),
appleRedirectHandlerPOST:
(_h = thirdPartyImplementation.appleRedirectHandlerPOST) === null || _h === void 0
(_j = thirdPartyImplementation.appleRedirectHandlerPOST) === null || _j === void 0
? void 0
: _h.bind(thirdPartyAPIImplementation_1.default(this)),
: _j.bind(thirdPartyAPIImplementation_1.default(this)),
};
}
exports.default = getAPIImplementation;
4 changes: 3 additions & 1 deletion lib/build/recipe/thirdpartyemailpassword/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default class Wrapper {
static getUsersByEmail(email: string, userContext?: any): Promise<User[]>;
static createResetPasswordToken(
userId: string,
email: string,
userContext?: any
): Promise<
| {
Expand All @@ -69,7 +70,8 @@ export default class Wrapper {
): Promise<
| {
status: "OK";
userId?: string | undefined;
email: string;
userId: string;
}
| {
status: "RESET_PASSWORD_INVALID_TOKEN_ERROR";
Expand Down
Loading