AuthTemplatesValidation.tsx384 lines · main
| 1 | import * as z from 'zod' |
| 2 | |
| 3 | import type { AuthTemplate, TemplateVariable, TemplateVariableName } from './EmailTemplates.types' |
| 4 | |
| 5 | const TemplateVariables: Record<TemplateVariableName, TemplateVariable> = { |
| 6 | ConfirmationURL: { |
| 7 | name: 'ConfirmationURL', |
| 8 | value: '{{ .ConfirmationURL }}', |
| 9 | description: 'URL to confirm the email address for the new account', |
| 10 | }, |
| 11 | Token: { |
| 12 | name: 'Token', |
| 13 | value: '{{ .Token }}', |
| 14 | description: '6-digit numeric email OTP', |
| 15 | }, |
| 16 | TokenHash: { |
| 17 | name: 'TokenHash', |
| 18 | value: '{{ .TokenHash }}', |
| 19 | description: 'Hashed token used in the URL, useful for constructing your own email link', |
| 20 | }, |
| 21 | SiteURL: { |
| 22 | name: 'SiteURL', |
| 23 | value: '{{ .SiteURL }}', |
| 24 | description: 'Redirect URL', |
| 25 | }, |
| 26 | Email: { |
| 27 | name: 'Email', |
| 28 | value: '{{ .Email }}', |
| 29 | description: "User's current email address", |
| 30 | }, |
| 31 | NewEmail: { |
| 32 | name: 'NewEmail', |
| 33 | value: '{{ .NewEmail }}', |
| 34 | description: "User's new email address", |
| 35 | }, |
| 36 | OldEmail: { |
| 37 | name: 'OldEmail', |
| 38 | value: '{{ .OldEmail }}', |
| 39 | description: "User's old email address", |
| 40 | }, |
| 41 | Phone: { |
| 42 | name: 'Phone', |
| 43 | value: '{{ .Phone }}', |
| 44 | description: "User's new phone number", |
| 45 | }, |
| 46 | OldPhone: { |
| 47 | name: 'OldPhone', |
| 48 | value: '{{ .OldPhone }}', |
| 49 | description: "User's old phone number", |
| 50 | }, |
| 51 | Provider: { |
| 52 | name: 'Provider', |
| 53 | value: '{{ .Provider }}', |
| 54 | description: 'Provider of newly linked/unlinked identity', |
| 55 | }, |
| 56 | FactorType: { |
| 57 | name: 'FactorType', |
| 58 | value: '{{ .FactorType }}', |
| 59 | description: 'Type of newly enrolled/unenrolled MFA factor', |
| 60 | }, |
| 61 | Data: { |
| 62 | name: 'Data', |
| 63 | value: '{{ .Data }}', |
| 64 | description: ( |
| 65 | <> |
| 66 | User's <code className="text-code-inline">user_metadata</code>, use this to personalize the |
| 67 | message |
| 68 | </> |
| 69 | ), |
| 70 | }, |
| 71 | RedirectTo: { |
| 72 | name: 'RedirectTo', |
| 73 | value: '{{ .RedirectTo }}', |
| 74 | description: ( |
| 75 | <> |
| 76 | Redirect URL passed as the <code className="text-code-inline">redirectTo</code> option in |
| 77 | the auth method call |
| 78 | </> |
| 79 | ), |
| 80 | }, |
| 81 | } |
| 82 | |
| 83 | const CONFIRMATION: AuthTemplate = { |
| 84 | id: 'CONFIRMATION', |
| 85 | type: 'object', |
| 86 | title: 'Confirm sign up', |
| 87 | purpose: 'Ask users to confirm their email address after signing up', |
| 88 | properties: { |
| 89 | MAILER_SUBJECTS_CONFIRMATION: { title: 'Subject', type: 'string' }, |
| 90 | MAILER_TEMPLATES_CONFIRMATION_CONTENT: { title: 'Body', type: 'code' }, |
| 91 | }, |
| 92 | variables: [ |
| 93 | TemplateVariables.ConfirmationURL, |
| 94 | TemplateVariables.Token, |
| 95 | TemplateVariables.TokenHash, |
| 96 | TemplateVariables.SiteURL, |
| 97 | TemplateVariables.Email, |
| 98 | TemplateVariables.Data, |
| 99 | TemplateVariables.RedirectTo, |
| 100 | ], |
| 101 | validationSchema: z.object({ |
| 102 | MAILER_SUBJECTS_CONFIRMATION: z.string().min(1, 'Subject is required.'), |
| 103 | }), |
| 104 | misc: { |
| 105 | emailTemplateType: 'authentication', |
| 106 | }, |
| 107 | } |
| 108 | |
| 109 | const INVITE: AuthTemplate = { |
| 110 | id: 'INVITE', |
| 111 | type: 'object', |
| 112 | title: 'Invite user', |
| 113 | purpose: "Invite users who don't yet have an account to sign up", |
| 114 | properties: { |
| 115 | MAILER_SUBJECTS_INVITE: { title: 'Subject', type: 'string' }, |
| 116 | MAILER_TEMPLATES_INVITE_CONTENT: { title: 'Body', type: 'code' }, |
| 117 | }, |
| 118 | variables: [ |
| 119 | TemplateVariables.ConfirmationURL, |
| 120 | TemplateVariables.Token, |
| 121 | TemplateVariables.TokenHash, |
| 122 | TemplateVariables.SiteURL, |
| 123 | TemplateVariables.Email, |
| 124 | TemplateVariables.Data, |
| 125 | TemplateVariables.RedirectTo, |
| 126 | ], |
| 127 | validationSchema: z.object({ |
| 128 | MAILER_SUBJECTS_INVITE: z.string().min(1, 'Subject is required.'), |
| 129 | }), |
| 130 | misc: { |
| 131 | emailTemplateType: 'authentication', |
| 132 | }, |
| 133 | } |
| 134 | |
| 135 | const MAGIC_LINK: AuthTemplate = { |
| 136 | id: 'MAGIC_LINK', |
| 137 | type: 'object', |
| 138 | title: 'Magic link or OTP', |
| 139 | purpose: 'Send a one-time sign-in link or one-time password', |
| 140 | properties: { |
| 141 | MAILER_SUBJECTS_MAGIC_LINK: { title: 'Subject', type: 'string' }, |
| 142 | MAILER_TEMPLATES_MAGIC_LINK_CONTENT: { title: 'Body', type: 'code' }, |
| 143 | }, |
| 144 | variables: [ |
| 145 | TemplateVariables.ConfirmationURL, |
| 146 | TemplateVariables.Token, |
| 147 | TemplateVariables.TokenHash, |
| 148 | TemplateVariables.SiteURL, |
| 149 | TemplateVariables.Email, |
| 150 | TemplateVariables.Data, |
| 151 | TemplateVariables.RedirectTo, |
| 152 | ], |
| 153 | validationSchema: z.object({ |
| 154 | MAILER_SUBJECTS_MAGIC_LINK: z.string().min(1, 'Subject is required.'), |
| 155 | }), |
| 156 | misc: { |
| 157 | emailTemplateType: 'authentication', |
| 158 | }, |
| 159 | } |
| 160 | |
| 161 | const EMAIL_CHANGE: AuthTemplate = { |
| 162 | id: 'EMAIL_CHANGE', |
| 163 | type: 'object', |
| 164 | title: 'Change email address', |
| 165 | purpose: 'Ask users to verify their new email address after changing it', |
| 166 | properties: { |
| 167 | MAILER_SUBJECTS_EMAIL_CHANGE: { title: 'Subject', type: 'string' }, |
| 168 | MAILER_TEMPLATES_EMAIL_CHANGE_CONTENT: { title: 'Body', type: 'code' }, |
| 169 | }, |
| 170 | variables: [ |
| 171 | TemplateVariables.ConfirmationURL, |
| 172 | TemplateVariables.Token, |
| 173 | TemplateVariables.TokenHash, |
| 174 | TemplateVariables.SiteURL, |
| 175 | TemplateVariables.Email, |
| 176 | TemplateVariables.NewEmail, |
| 177 | TemplateVariables.Data, |
| 178 | TemplateVariables.RedirectTo, |
| 179 | ], |
| 180 | validationSchema: z.object({ |
| 181 | MAILER_SUBJECTS_EMAIL_CHANGE: z.string().min(1, 'Subject is required.'), |
| 182 | }), |
| 183 | misc: { |
| 184 | emailTemplateType: 'authentication', |
| 185 | }, |
| 186 | } |
| 187 | |
| 188 | const RECOVERY: AuthTemplate = { |
| 189 | id: 'RECOVERY', |
| 190 | type: 'object', |
| 191 | title: 'Reset password', |
| 192 | purpose: 'Allow users to reset their password if they forget it', |
| 193 | properties: { |
| 194 | MAILER_SUBJECTS_RECOVERY: { title: 'Subject', type: 'string' }, |
| 195 | MAILER_TEMPLATES_RECOVERY_CONTENT: { title: 'Body', type: 'code' }, |
| 196 | }, |
| 197 | variables: [ |
| 198 | TemplateVariables.ConfirmationURL, |
| 199 | TemplateVariables.Token, |
| 200 | TemplateVariables.TokenHash, |
| 201 | TemplateVariables.SiteURL, |
| 202 | TemplateVariables.Email, |
| 203 | TemplateVariables.Data, |
| 204 | TemplateVariables.RedirectTo, |
| 205 | ], |
| 206 | validationSchema: z.object({ |
| 207 | MAILER_SUBJECTS_RECOVERY: z.string().min(1, 'Subject is required.'), |
| 208 | }), |
| 209 | misc: { |
| 210 | emailTemplateType: 'authentication', |
| 211 | }, |
| 212 | } |
| 213 | |
| 214 | const REAUTHENTICATION: AuthTemplate = { |
| 215 | id: 'REAUTHENTICATION', |
| 216 | type: 'object', |
| 217 | title: 'Reauthentication', |
| 218 | purpose: 'Ask users to re-authenticate before performing a sensitive action', |
| 219 | properties: { |
| 220 | MAILER_SUBJECTS_REAUTHENTICATION: { title: 'Subject', type: 'string' }, |
| 221 | MAILER_TEMPLATES_REAUTHENTICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 222 | }, |
| 223 | variables: [ |
| 224 | TemplateVariables.Token, |
| 225 | TemplateVariables.SiteURL, |
| 226 | TemplateVariables.Email, |
| 227 | TemplateVariables.Data, |
| 228 | ], |
| 229 | validationSchema: z.object({ |
| 230 | MAILER_SUBJECTS_REAUTHENTICATION: z.string().min(1, 'Subject is required.'), |
| 231 | }), |
| 232 | misc: { |
| 233 | emailTemplateType: 'authentication', |
| 234 | }, |
| 235 | } |
| 236 | |
| 237 | // Notifications |
| 238 | const PASSWORD_CHANGED_NOTIFICATION: AuthTemplate = { |
| 239 | id: 'PASSWORD_CHANGED_NOTIFICATION', |
| 240 | type: 'object', |
| 241 | title: 'Password changed', |
| 242 | purpose: 'Notify users when their password has changed', |
| 243 | properties: { |
| 244 | MAILER_SUBJECTS_PASSWORD_CHANGED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 245 | MAILER_TEMPLATES_PASSWORD_CHANGED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 246 | }, |
| 247 | variables: [TemplateVariables.Email, TemplateVariables.Data], |
| 248 | validationSchema: z.object({ |
| 249 | MAILER_SUBJECTS_PASSWORD_CHANGED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 250 | }), |
| 251 | misc: { |
| 252 | emailTemplateType: 'security', |
| 253 | }, |
| 254 | } |
| 255 | |
| 256 | const EMAIL_CHANGED_NOTIFICATION: AuthTemplate = { |
| 257 | id: 'EMAIL_CHANGED_NOTIFICATION', |
| 258 | type: 'object', |
| 259 | title: 'Email address changed', |
| 260 | purpose: 'Notify users when their email address has changed', |
| 261 | properties: { |
| 262 | MAILER_SUBJECTS_EMAIL_CHANGED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 263 | MAILER_TEMPLATES_EMAIL_CHANGED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 264 | }, |
| 265 | variables: [TemplateVariables.Email, TemplateVariables.OldEmail, TemplateVariables.Data], |
| 266 | validationSchema: z.object({ |
| 267 | MAILER_SUBJECTS_EMAIL_CHANGED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 268 | }), |
| 269 | misc: { |
| 270 | emailTemplateType: 'security', |
| 271 | }, |
| 272 | } |
| 273 | |
| 274 | const PHONE_CHANGED_NOTIFICATION: AuthTemplate = { |
| 275 | id: 'PHONE_CHANGED_NOTIFICATION', |
| 276 | type: 'object', |
| 277 | title: 'Phone number changed', |
| 278 | purpose: 'Notify users when their phone number has changed', |
| 279 | properties: { |
| 280 | MAILER_SUBJECTS_PHONE_CHANGED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 281 | MAILER_TEMPLATES_PHONE_CHANGED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 282 | }, |
| 283 | variables: [ |
| 284 | TemplateVariables.Email, |
| 285 | TemplateVariables.Phone, |
| 286 | TemplateVariables.OldPhone, |
| 287 | TemplateVariables.Data, |
| 288 | ], |
| 289 | validationSchema: z.object({ |
| 290 | MAILER_SUBJECTS_PHONE_CHANGED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 291 | }), |
| 292 | misc: { |
| 293 | emailTemplateType: 'security', |
| 294 | }, |
| 295 | } |
| 296 | |
| 297 | const IDENTITY_LINKED_NOTIFICATION: AuthTemplate = { |
| 298 | id: 'IDENTITY_LINKED_NOTIFICATION', |
| 299 | type: 'object', |
| 300 | title: 'Identity linked', |
| 301 | purpose: 'Notify users when a new identity has been linked to their account', |
| 302 | properties: { |
| 303 | MAILER_SUBJECTS_IDENTITY_LINKED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 304 | MAILER_TEMPLATES_IDENTITY_LINKED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 305 | }, |
| 306 | variables: [TemplateVariables.Email, TemplateVariables.Provider, TemplateVariables.Data], |
| 307 | validationSchema: z.object({ |
| 308 | MAILER_SUBJECTS_IDENTITY_LINKED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 309 | }), |
| 310 | misc: { |
| 311 | emailTemplateType: 'security', |
| 312 | }, |
| 313 | } |
| 314 | |
| 315 | const IDENTITY_UNLINKED_NOTIFICATION: AuthTemplate = { |
| 316 | id: 'IDENTITY_UNLINKED_NOTIFICATION', |
| 317 | type: 'object', |
| 318 | title: 'Identity unlinked', |
| 319 | purpose: 'Notify users when an identity has been unlinked from their account', |
| 320 | properties: { |
| 321 | MAILER_SUBJECTS_IDENTITY_UNLINKED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 322 | MAILER_TEMPLATES_IDENTITY_UNLINKED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 323 | }, |
| 324 | variables: [TemplateVariables.Email, TemplateVariables.Provider, TemplateVariables.Data], |
| 325 | validationSchema: z.object({ |
| 326 | MAILER_SUBJECTS_IDENTITY_UNLINKED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 327 | }), |
| 328 | misc: { |
| 329 | emailTemplateType: 'security', |
| 330 | }, |
| 331 | } |
| 332 | |
| 333 | const MFA_FACTOR_ENROLLED_NOTIFICATION: AuthTemplate = { |
| 334 | id: 'MFA_FACTOR_ENROLLED_NOTIFICATION', |
| 335 | type: 'object', |
| 336 | title: 'MFA method added', |
| 337 | purpose: 'Notify users when an MFA method has been added to their account', |
| 338 | properties: { |
| 339 | MAILER_SUBJECTS_MFA_FACTOR_ENROLLED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 340 | MAILER_TEMPLATES_MFA_FACTOR_ENROLLED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 341 | }, |
| 342 | variables: [TemplateVariables.Email, TemplateVariables.FactorType, TemplateVariables.Data], |
| 343 | validationSchema: z.object({ |
| 344 | MAILER_SUBJECTS_MFA_FACTOR_ENROLLED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 345 | }), |
| 346 | misc: { |
| 347 | emailTemplateType: 'security', |
| 348 | }, |
| 349 | } |
| 350 | |
| 351 | const MFA_FACTOR_UNENROLLED_NOTIFICATION: AuthTemplate = { |
| 352 | id: 'MFA_FACTOR_UNENROLLED_NOTIFICATION', |
| 353 | type: 'object', |
| 354 | title: 'MFA method removed', |
| 355 | purpose: 'Notify users when an MFA method has been removed from their account', |
| 356 | properties: { |
| 357 | MAILER_SUBJECTS_MFA_FACTOR_UNENROLLED_NOTIFICATION: { title: 'Subject', type: 'string' }, |
| 358 | MAILER_TEMPLATES_MFA_FACTOR_UNENROLLED_NOTIFICATION_CONTENT: { title: 'Body', type: 'code' }, |
| 359 | }, |
| 360 | variables: [TemplateVariables.Email, TemplateVariables.FactorType, TemplateVariables.Data], |
| 361 | validationSchema: z.object({ |
| 362 | MAILER_SUBJECTS_MFA_FACTOR_UNENROLLED_NOTIFICATION: z.string().min(1, 'Subject is required.'), |
| 363 | }), |
| 364 | misc: { |
| 365 | emailTemplateType: 'security', |
| 366 | }, |
| 367 | } |
| 368 | |
| 369 | export const TEMPLATES_SCHEMAS = [ |
| 370 | CONFIRMATION, |
| 371 | INVITE, |
| 372 | MAGIC_LINK, |
| 373 | EMAIL_CHANGE, |
| 374 | RECOVERY, |
| 375 | REAUTHENTICATION, |
| 376 | // Notifications |
| 377 | PASSWORD_CHANGED_NOTIFICATION, |
| 378 | EMAIL_CHANGED_NOTIFICATION, |
| 379 | PHONE_CHANGED_NOTIFICATION, |
| 380 | IDENTITY_LINKED_NOTIFICATION, |
| 381 | IDENTITY_UNLINKED_NOTIFICATION, |
| 382 | MFA_FACTOR_ENROLLED_NOTIFICATION, |
| 383 | MFA_FACTOR_UNENROLLED_NOTIFICATION, |
| 384 | ] |