(queries: Queries, connectorLibrary: ConnectorLibrary)
| 50 | }; |
| 51 | |
| 52 | export const createPasscodeLibrary = (queries: Queries, connectorLibrary: ConnectorLibrary) => { |
| 53 | const { |
| 54 | consumePasscode, |
| 55 | deletePasscodesByIds, |
| 56 | findUnconsumedPasscodeByJtiAndType, |
| 57 | findUnconsumedPasscodesByJtiAndType, |
| 58 | findUnconsumedPasscodeByIdentifierAndType, |
| 59 | findUnconsumedPasscodesByIdentifierAndType, |
| 60 | increasePasscodeTryCount, |
| 61 | insertPasscode, |
| 62 | } = queries.passcodes; |
| 63 | const { getMessageConnector } = connectorLibrary; |
| 64 | |
| 65 | const createPasscode = async ( |
| 66 | jti: string | undefined, |
| 67 | type: TemplateType, |
| 68 | payload: { phone: string } | { email: string } |
| 69 | ) => { |
| 70 | // Disable existing passcodes. |
| 71 | const passcodes = jti |
| 72 | ? // Session based flows. E.g. SignIn, Register, etc. |
| 73 | await findUnconsumedPasscodesByJtiAndType(jti, type) |
| 74 | : // Generic flow. E.g. Triggered by management API |
| 75 | await findUnconsumedPasscodesByIdentifierAndType({ type, ...payload }); |
| 76 | |
| 77 | if (passcodes.length > 0) { |
| 78 | await deletePasscodesByIds(passcodes.map(({ id }) => id)); |
| 79 | } |
| 80 | |
| 81 | return insertPasscode({ |
| 82 | id: nanoid(), |
| 83 | interactionJti: jti, |
| 84 | type, |
| 85 | code: randomCode(), |
| 86 | ...payload, |
| 87 | }); |
| 88 | }; |
| 89 | |
| 90 | /** |
| 91 | * |
| 92 | * @param {Passcode} passcode The passcode object being sent. |
| 93 | * @param {SendPasscodeContextPayload} contextPayload The extra context information for the verification code email template. |
| 94 | */ |
| 95 | const sendPasscode = async (passcode: Passcode, contextPayload?: SendPasscodeContextPayload) => { |
| 96 | const emailOrPhone = passcode.email ?? passcode.phone; |
| 97 | |
| 98 | if (!emailOrPhone) { |
| 99 | throw new RequestError('verification_code.phone_email_empty'); |
| 100 | } |
| 101 | |
| 102 | const templateType = resolveTemplateType(passcode.type); |
| 103 | const expectType = passcode.phone ? ConnectorType.Sms : ConnectorType.Email; |
| 104 | const connector = await getMessageConnector(expectType); |
| 105 | const { dbEntry, metadata, sendMessage } = connector; |
| 106 | |
| 107 | const { ip, ...payloadContext } = contextPayload ?? {}; |
| 108 | |
| 109 | const response = await sendMessage({ |
no outgoing calls
no test coverage detected