Closed ErikGoH closed 1 year ago
I don't know if the login route should also lowercase the email or the create should save the email as is sent, my quick fix will be to lowercase the email before sending the login request as I have had some users report that they couldn't login even when the browser password manager saved their credentials.
Yeah, lowercasing all emails before sending them to login is the correct workaround. I guess I'm always doing that on the client side, so I forgot about it. I've also been bitten by email casing issues in superlogin and moved towards lowercasing everything, e.g. in:
The .toLowerCase().trim()
isn't yet included in the local strategy. Would be a good idea to add it there, too:
https://github.com/perfood/couch-auth/blob/master/src/local.ts#L52
Should be also fine when using username as login, since that's validated with /^[a-z0-9_-]{3,16}$/
I was creating some test users when I found the following behavior:
It took me a while to figure out why I was getting the Unauthorized message if I had just created the user, after checking that my configuration was correct (I disabled everything related to email confirmation) I had to start adding console.logs in the
node_modules > couch-auth
filesFinally realized the thing that was happening when I checked
node_modules/@perfood/couch-auth/lib/user/DbManager.js
that everything was correct but when querying theauth.email
view it wasn't returning anything thats when I realized that the emails are saved in lower case.I don't know if the login route should also lowercase the email or the create should save the email as is sent, my quick fix will be to lowercase the email before sending the login request as I have had some users report that they couldn't login even when the browser password manager saved their credentials.
PS: I am currently using my fork https://github.com/ErikGoH/superlogin-next/tree/main-keycode but I don't think there are any significant changes My
package.json
looks like thisMy config
``` const config = { security: { loginOnRegistration: true, }, testMode: { debugEmail: this.configService.get('TEST_MODE_DEBUG_EMAIL') === 'true', noEmail: this.configService.get('TEST_MODE_NO_EMAIL') === 'true', }, dbServer: { protocol: this.configService.get<'http://' | 'https://'>('DB_PROTOCOL'), host: this.configService.get('DB_HOST'), user: this.configService.get('DB_USER'), password: this.configService.get('DB_PASSWORD'), userDB: this.configService.get('DB_USERDB_SL'), couchAuthDB: this.configService.get('DB_COUCH_AUTHDB'), publicURL: this.configService.get('DB_PUBLIC_URL'), }, mailer: { fromEmail: this.configService.get('MAILER_FROMUSER'), transport: this.configService.get('MAILER_SENDGRID_APIKEY') ? nodemailerSendgrid : undefined, options: this.configService.get('MAILER_SENDGRID_APIKEY') ? { apiKey: this.configService.get( 'MAILER_SENDGRID_APIKEY', ) as string, } : { host: this.configService.get('MAILER_HOST'), port: this.configService.get('MAILER_PORT'), secure: this.configService.get('MAILER_PORT') === '465' ? true : false, auth: { user: this.configService.get('MAILER_AUTHUSER'), pass: this.configService.get('MAILER_PASSWORD'), }, }, }, local: { // Custom names for the username and password fields in your sign-in form usernameField: 'email', passwordField: 'password', emailUsername: true, usernameLogin: false, // Send out a confirm email after each user signs up with local login sendConfirmEmail: false, // Require the email be confirmed before the user can login or before his changed email is updated requireEmailConfirm: false, }, providers: { google: { credentials: { clientID: this.configService.get('GOOGLE_CLIENT_ID'), clientSecret: this.configService.get('GOOGLE_CLIENT_SECRET'), audience: [ this.configService.get('GOOGLE_CLIENT_ID'), this.configService.get('GOOGLE_CLIENT_ID_CORDOVA'), ], }, options: { scope: ['email'], }, template: path.join( __dirname, './templates/oauth/my-custom-secure-auth-callback.ejs', ), templateTest: path.join( __dirname, './templates/oauth/my-custom-secure-auth-callback-test.ejs', ), }, facebook: { credentials: { clientID: this.configService.get('FACEBOOK_APP_ID'), clientSecret: this.configService.get('FACEBOOK_APP_SECRET'), profileFields: ['id', 'displayName', 'name', 'emails'], fbGraphVersion: 'v3.2', }, options: { scope: ['email', 'public_profile'], }, template: path.join( __dirname, './templates/oauth/my-custom-secure-auth-callback.ejs', ), }, }, userDBs: { defaultDBs: { private: ['interviewer'], }, model: { _default: { designDocs: [], }, interviewer: { type: 'private', adminRoles: ['admin', 'AdminActive'], appendSeparator: this.configService.get('DB_APPEND_SEPARATOR'), designDocs: [], //'consumos', 'sesiones', 'seguimientos' }, }, designDocDir: path.join(__dirname, './ddocs'), }, userModel: { whitelist: ['roles'], customValidators: { roleValidator: function (value: string[], validRoles: string[]) { if (!value || value.length < 1) { return 'El rol es requerido'; } try { value.forEach((role) => { if (!validRoles.includes(role)) { throw new Error(`: El rol no puede ser ${role}`); } }); } catch (error) { type validatorError = { message?: string }; const posibleError = error as validatorError; return posibleError?.message ?? 'Ocurrio un error'; } return null; }, }, validate: { roles: { roleValidator: ['user', 'Interviewer', 'Admin'], }, }, }, }; ```