-
Notifications
You must be signed in to change notification settings - Fork 11
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
feat: rename functions and refactor native library calls into separate functions #126
Changes from 5 commits
439fe7c
05a3e37
4d88f22
f709930
e38fff8
dbe0aa2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,14 @@ import { GeneralErrorResponse, User } from "../../types"; | |
import { getNormalisedUserContext } from "../../utils"; | ||
import { RecipeFunctionOptions } from "../recipeModule/types"; | ||
import Recipe from "./recipe"; | ||
import { CredentialPayload, ResidentKey, UserInput, UserVerification } from "./types"; | ||
import { | ||
CredentialPayload, | ||
ResidentKey, | ||
UserInput, | ||
UserVerification, | ||
RegistrationOptions, | ||
AuthenticationOptions, | ||
} from "./types"; | ||
|
||
export default class RecipeWrapper { | ||
static init(config?: UserInput) { | ||
|
@@ -39,7 +46,7 @@ export default class RecipeWrapper { | |
* | ||
* @returns `{ status: "OK", ...}` if successful along a description of the created webauthn details (challenge, etc.) | ||
*/ | ||
static registerOptions( | ||
static getRegisterOptions( | ||
input: { options?: RecipeFunctionOptions; userContext: any } & ( | ||
| { email: string } | ||
| { recoverAccountToken: string } | ||
|
@@ -90,7 +97,7 @@ export default class RecipeWrapper { | |
fetchResponse: Response; | ||
} | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.registerOptions({ | ||
return Recipe.getInstanceOrThrow().recipeImplementation.getRegisterOptions({ | ||
...input, | ||
userContext: getNormalisedUserContext(input?.userContext), | ||
}); | ||
|
@@ -108,7 +115,7 @@ export default class RecipeWrapper { | |
* | ||
* @returns `{ status: "OK", ...}` if successful along a description of the webauthn options (challenge, etc.) | ||
*/ | ||
static signInOptions(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
static getSignInOptions(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
| { | ||
status: "OK"; | ||
webauthnGeneratedOptionsId: string; | ||
|
@@ -123,7 +130,7 @@ export default class RecipeWrapper { | |
} | ||
| GeneralErrorResponse | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.signInOptions({ | ||
return Recipe.getInstanceOrThrow().recipeImplementation.getSignInOptions({ | ||
...input, | ||
userContext: getNormalisedUserContext(input?.userContext), | ||
}); | ||
|
@@ -217,14 +224,14 @@ export default class RecipeWrapper { | |
* | ||
* @returns `{ status: "OK", ...}` if successful along with a boolean indicating existence | ||
*/ | ||
static emailExists(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
static getEmailExists(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
| { | ||
status: "OK"; | ||
exists: boolean; | ||
} | ||
| GeneralErrorResponse | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.emailExists({ | ||
return Recipe.getInstanceOrThrow().recipeImplementation.getEmailExists({ | ||
...input, | ||
userContext: input?.userContext, | ||
}); | ||
|
@@ -298,6 +305,45 @@ export default class RecipeWrapper { | |
}); | ||
} | ||
|
||
/** | ||
* Register user with the passed options by using native webauthn functions. | ||
* | ||
* It uses `@simplewebauthn/browser` to make the webauthn calls. | ||
* | ||
* @param registrationOptions Options to pass for the registration. | ||
* | ||
* @returns `{ status: "OK", ...}` if successful along with registration response received | ||
*/ | ||
static registerUser(input: { registrationOptions: RegistrationOptions }): Promise< | ||
| { | ||
status: "OK"; | ||
registrationResponse: RegistrationResponseJSON; | ||
} | ||
| { status: "AUTHENTICATOR_ALREADY_REGISTERED" } | ||
| { status: "FAILED_TO_REGISTER_USER"; error: any } | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.registerUser(input); | ||
} | ||
|
||
/** | ||
* Authenticate the user with the passed options by using native webauthn functions. | ||
* | ||
* It uses `@simplewebauthn/browser` to make the webauthn calls. | ||
* | ||
* @param authenticationOptions Options to pass for the authentication. | ||
* | ||
* @returns `{ status: "OK", ...}` if successful along with authentication response received | ||
*/ | ||
static authenticateUser(input: { authenticationOptions: AuthenticationOptions }): Promise< | ||
| { | ||
status: "OK"; | ||
authenticationResponse: AuthenticationResponseJSON; | ||
} | ||
| { status: "FAILED_TO_AUTHENTICATE_USER"; error: any } | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.authenticateUser(input); | ||
} | ||
|
||
/** | ||
* Register the new device and signup the user with the passed email ID. | ||
* | ||
|
@@ -311,7 +357,7 @@ export default class RecipeWrapper { | |
* | ||
* @returns `{ status: "OK", ...}` if successful along a description of the user details (id, etc.) and email | ||
*/ | ||
static registerAndSignUp(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
static registerUserWithSignUp(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
| { | ||
status: "OK"; | ||
user: User; | ||
|
@@ -338,8 +384,9 @@ export default class RecipeWrapper { | |
| { status: "INVALID_AUTHENTICATOR_ERROR"; reason: string; fetchResponse: Response } | ||
| { status: "EMAIL_ALREADY_EXISTS_ERROR"; fetchResponse: Response } | ||
| { status: "AUTHENTICATOR_ALREADY_REGISTERED" } | ||
| { status: "FAILED_TO_REGISTER_USER"; error: any } | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.registerAndSignUp({ | ||
return Recipe.getInstanceOrThrow().recipeImplementation.registerUserWithSignUp({ | ||
...input, | ||
userContext: input?.userContext, | ||
}); | ||
|
@@ -358,7 +405,11 @@ export default class RecipeWrapper { | |
* | ||
* @returns `{ status: "OK", ...}` if successful along a description of the user details (id, etc.) and email | ||
*/ | ||
static authenticateAndSignIn(input: { email: string; options?: RecipeFunctionOptions; userContext: any }): Promise< | ||
static authenticateUserWithSignIn(input: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. Sounds a bit confusing |
||
email: string; | ||
options?: RecipeFunctionOptions; | ||
userContext: any; | ||
}): Promise< | ||
| { | ||
status: "OK"; | ||
user: User; | ||
|
@@ -374,9 +425,10 @@ export default class RecipeWrapper { | |
reason: string; | ||
fetchResponse: Response; | ||
} | ||
| { status: "FAILED_TO_AUTHENTICATE_USER"; error: any } | ||
| GeneralErrorResponse | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.authenticateAndSignIn({ | ||
return Recipe.getInstanceOrThrow().recipeImplementation.authenticateUserWithSignIn({ | ||
...input, | ||
userContext: input?.userContext, | ||
}); | ||
|
@@ -395,7 +447,7 @@ export default class RecipeWrapper { | |
* | ||
* @returns `{ status: "OK", ...}` if successful along a description of the user details (id, etc.) and email | ||
*/ | ||
static registerAndRecoverAccount(input: { | ||
static registerUserWithRecoverAccount(input: { | ||
recoverAccountToken: string; | ||
options?: RecipeFunctionOptions; | ||
userContext: any; | ||
|
@@ -421,36 +473,41 @@ export default class RecipeWrapper { | |
| { status: "INVALID_GENERATED_OPTIONS_ERROR"; fetchResponse: Response } | ||
| { status: "INVALID_AUTHENTICATOR_ERROR"; reason: string; fetchResponse: Response } | ||
| { status: "AUTHENTICATOR_ALREADY_REGISTERED" } | ||
| { status: "FAILED_TO_REGISTER_USER"; error: any } | ||
> { | ||
return Recipe.getInstanceOrThrow().recipeImplementation.registerAndRecoverAccount({ | ||
return Recipe.getInstanceOrThrow().recipeImplementation.registerUserWithRecoverAccount({ | ||
...input, | ||
userContext: input?.userContext, | ||
}); | ||
} | ||
} | ||
|
||
const init = RecipeWrapper.init; | ||
const registerOptions = RecipeWrapper.registerOptions; | ||
const signInOptions = RecipeWrapper.signInOptions; | ||
const getRegisterOptions = RecipeWrapper.getRegisterOptions; | ||
const getSignInOptions = RecipeWrapper.getSignInOptions; | ||
const signUp = RecipeWrapper.signUp; | ||
const signIn = RecipeWrapper.signIn; | ||
const emailExists = RecipeWrapper.emailExists; | ||
const getEmailExists = RecipeWrapper.getEmailExists; | ||
const generateRecoverAccountToken = RecipeWrapper.generateRecoverAccountToken; | ||
const recoverAccount = RecipeWrapper.recoverAccount; | ||
const registerAndSignup = RecipeWrapper.registerAndSignUp; | ||
const authenticateAndSignIn = RecipeWrapper.authenticateAndSignIn; | ||
const registerAndRecoverAccount = RecipeWrapper.registerAndRecoverAccount; | ||
const registerUserWithSignUp = RecipeWrapper.registerUserWithSignUp; | ||
const authenticateUserWithSignIn = RecipeWrapper.authenticateUserWithSignIn; | ||
const registerUserWithRecoverAccount = RecipeWrapper.registerUserWithRecoverAccount; | ||
const registerUser = RecipeWrapper.registerUser; | ||
const authenticateUser = RecipeWrapper.authenticateUser; | ||
|
||
export { | ||
init, | ||
registerOptions, | ||
signInOptions, | ||
getRegisterOptions, | ||
getSignInOptions, | ||
signUp, | ||
signIn, | ||
emailExists, | ||
getEmailExists, | ||
generateRecoverAccountToken, | ||
recoverAccount, | ||
registerAndSignup, | ||
authenticateAndSignIn, | ||
registerAndRecoverAccount, | ||
registerUserWithSignUp, | ||
authenticateUserWithSignIn, | ||
registerUserWithRecoverAccount, | ||
registerUser, | ||
authenticateUser, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,7 @@ export default function getRecipeImplementation( | |
const querier = new Querier(recipeImplInput.recipeId, recipeImplInput.appInfo); | ||
|
||
return { | ||
registerOptions: async function ({ | ||
getRegisterOptions: async function ({ | ||
options, | ||
userContext, | ||
email, | ||
|
@@ -115,7 +115,7 @@ export default function getRecipeImplementation( | |
fetchResponse, | ||
}; | ||
}, | ||
signInOptions: async function ({ email, options, userContext }) { | ||
getSignInOptions: async function ({ email, options, userContext }) { | ||
const { jsonBody, fetchResponse } = await querier.post< | ||
| { | ||
status: "OK"; | ||
|
@@ -244,7 +244,7 @@ export default function getRecipeImplementation( | |
fetchResponse, | ||
}; | ||
}, | ||
emailExists: async function ({ email, options, userContext }) { | ||
getEmailExists: async function ({ email, options, userContext }) { | ||
const { jsonBody, fetchResponse } = await querier.get< | ||
| { | ||
status: "OK"; | ||
|
@@ -354,9 +354,29 @@ export default function getRecipeImplementation( | |
fetchResponse, | ||
}; | ||
}, | ||
registerAndSignUp: async function ({ email, options, userContext }) { | ||
registerUser: async function ({ registrationOptions }) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think this should contain some credential reference in the name, as the main purpose of this method is to generate the credential for a user (in order for the credential to be registered - either on sign up or, in the future, on registerCredential in their "profile" ) |
||
let registrationResponse: RegistrationResponseJSON; | ||
try { | ||
registrationResponse = await startRegistration({ optionsJSON: registrationOptions }); | ||
} catch (error: any) { | ||
if (error.name === "InvalidStateError") { | ||
return { status: "AUTHENTICATOR_ALREADY_REGISTERED" }; | ||
} | ||
|
||
return { | ||
status: "FAILED_TO_REGISTER_USER", | ||
error: error, | ||
}; | ||
} | ||
|
||
return { | ||
status: "OK", | ||
registrationResponse, | ||
}; | ||
}, | ||
registerUserWithSignUp: async function ({ email, options, userContext }) { | ||
// Get the registration options by using the passed email ID. | ||
const registrationOptions = await this.registerOptions({ options, userContext, email }); | ||
const registrationOptions = await this.getRegisterOptions({ options, userContext, email }); | ||
if (registrationOptions?.status !== "OK") { | ||
// If we did not get an OK status, we need to return the error as is. | ||
|
||
|
@@ -371,56 +391,63 @@ export default function getRecipeImplementation( | |
} | ||
|
||
// We should have received a valid registration options response. | ||
let registrationResponse: RegistrationResponseJSON; | ||
try { | ||
registrationResponse = await startRegistration({ optionsJSON: registrationOptions }); | ||
} catch (error: any) { | ||
if (error.name === "InvalidStateError") { | ||
return { status: "AUTHENTICATOR_ALREADY_REGISTERED" }; | ||
} | ||
|
||
throw error; | ||
const registerUserResponse = await this.registerUser({ registrationOptions }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here. The name should indicate that this is about the credential and not the user. |
||
if (registerUserResponse.status !== "OK") { | ||
return registerUserResponse; | ||
} | ||
|
||
// We should have a valid registration response for the passed credentials | ||
// and we are good to go ahead and verify them. | ||
return await this.signUp({ | ||
webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, | ||
credential: registrationResponse, | ||
credential: registerUserResponse.registrationResponse, | ||
options, | ||
userContext, | ||
}); | ||
}, | ||
authenticateAndSignIn: async function ({ email, options, userContext }) { | ||
authenticateUser: async function ({ authenticationOptions }) { | ||
let authenticationResponse: AuthenticationResponseJSON; | ||
try { | ||
authenticationResponse = await startAuthentication({ optionsJSON: authenticationOptions }); | ||
} catch (error: any) { | ||
return { | ||
status: "FAILED_TO_AUTHENTICATE_USER", | ||
error: error, | ||
}; | ||
} | ||
|
||
return { | ||
status: "OK", | ||
authenticationResponse: authenticationResponse, | ||
}; | ||
}, | ||
authenticateUserWithSignIn: async function ({ email, options, userContext }) { | ||
// Make a call to get the sign in options using the entered email ID. | ||
const signInOptions = await this.signInOptions({ email, options, userContext }); | ||
const signInOptions = await this.getSignInOptions({ email, options, userContext }); | ||
if (signInOptions?.status !== "OK") { | ||
// We want to return the error as is if status was not "OK" | ||
return signInOptions; | ||
} | ||
|
||
// We should have the options ready and are good to start the authentication | ||
let authenticationResponse: AuthenticationResponseJSON; | ||
try { | ||
authenticationResponse = await startAuthentication({ optionsJSON: signInOptions }); | ||
} catch (error: any) { | ||
// TODO: Do we need to do something with the error besides throwing it? | ||
throw error; | ||
const authenticateUserResponse = await this.authenticateUser({ authenticationOptions: signInOptions }); | ||
if (authenticateUserResponse.status !== "OK") { | ||
return authenticateUserResponse; | ||
} | ||
|
||
// We should have a valid authentication response at this point so we can | ||
// go ahead and sign in the user. | ||
return await this.signIn({ | ||
webauthnGeneratedOptionsId: signInOptions.webauthnGeneratedOptionsId, | ||
credential: authenticationResponse, | ||
credential: authenticateUserResponse.authenticationResponse, | ||
options: options, | ||
userContext: userContext, | ||
}); | ||
}, | ||
registerAndRecoverAccount: async function ({ recoverAccountToken, options, userContext }) { | ||
registerUserWithRecoverAccount: async function ({ recoverAccountToken, options, userContext }) { | ||
// Get the registration options based on the recoverAccountToken and | ||
// register the device against the user. | ||
const registrationOptions = await this.registerOptions({ options, userContext, recoverAccountToken }); | ||
const registrationOptions = await this.getRegisterOptions({ options, userContext, recoverAccountToken }); | ||
if (registrationOptions?.status !== "OK") { | ||
// If we did not get an OK status, we need to return the error as is. | ||
|
||
|
@@ -435,21 +462,15 @@ export default function getRecipeImplementation( | |
} | ||
|
||
// We should have received a valid registration options response. | ||
let registrationResponse: RegistrationResponseJSON; | ||
try { | ||
registrationResponse = await startRegistration({ optionsJSON: registrationOptions }); | ||
} catch (error: any) { | ||
if (error.name === "InvalidStateError") { | ||
return { status: "AUTHENTICATOR_ALREADY_REGISTERED" }; | ||
} | ||
|
||
throw error; | ||
const registerUserResponse = await this.registerUser({ registrationOptions }); | ||
if (registerUserResponse.status !== "OK") { | ||
return registerUserResponse; | ||
} | ||
|
||
return await this.recoverAccount({ | ||
token: recoverAccountToken, | ||
webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, | ||
credential: registrationResponse, | ||
credential: registerUserResponse.registrationResponse, | ||
options, | ||
userContext, | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this name sounds a bit confusing. What would be the difference between register and signUp ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with the changes, I have made them.