perfood / couch-auth Goto Github PK
View Code? Open in Web Editor NEWPowerful authentication for APIs and apps using CouchDB (or Cloudant) with Node >= 14
License: MIT License
Powerful authentication for APIs and apps using CouchDB (or Cloudant) with Node >= 14
License: MIT License
I've just migrated from superlogin
to couch-auth
, so first thanks for your work creating an up-to-date version of this framework!
Since the way usernames are stored and database names are chosen is differently in couch-auth
(key
value in user doc and <prefix><user-id>
for database name), I think the validation of the username could be less restrictive:
_
So my proposal would be to just use a regex like /^[A-Za-z0-9_-]{2,50}$/
or to make it configurable.
The users email address would be sent with the body and if that email address exists it would be sent an email with the username.
Currently if the user forgets their username there would be no way for them to ever gain access to their account.
Thanks for this brilliant updated fork of SuperLogin @LyteFM.
e.g. user:83bb2084d4f64cc99d8da95645904e3b
.
This would make it easier to add DDoc logic based on the UUID instead of the key
Currently, the plain text version of an email is simply the markdown source, when using the combined rendering approach
Hi, first of all thanks for this effort.
I followed the installation and it was installed successfully with no issues.
Following the simple minimalist configuration that will get me up and running right away resulted in an error.
I am using nodejs 16
var couchAuth = new CouchAuth(config);
^
TypeError: CouchAuth is not a constructor
at Object. (/home/mar/myapp/app.js:44:17)
at Module._compile (node:internal/modules/cjs/loader:1105:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
Hi ! I have been testing SuperLogin over the weekend for an upcoming project but it seems I have reached a blocking point.
I am trying to make the code example from the README work with my instance of CouchDB on my distant server.
The /register POST seems OK
curl --request POST \
--url http://localhost:3000/auth/register \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data '={
"name": "Joe Smith",
"username": "joesmith",
"email": "[email protected]",
"password": "bigsecret",
"confirmPassword": "bigsecret"
}'
{
"success": "Request processed."
}
but then there is nothing appearing in the Fauxton and of course the next step gives me some kind of error
curl --request POST \
--url http://localhost:3000/auth/login \
--header 'Authorization: Basic am9lc21pdGg6Ymlnc2VjcmV0'
{
"message": "Missing credentials"
}
And the CLI doesn't help me much as there is no error message at all, only POST /auth/register 200 516.158 ms - 32
On the CouchDB logs, there is only this POST /sl-users/_find 200 ok 5
when I perform the request.
My SuperLogin config is as following :
{
dbServer: {
protocol: 'https://',
host: 'krlx.ovh:6984',
user: 'admin',
password: 'redacted',
userDB: 'sl-users',
couchAuthDB: '_users'
},
mailer: {
fromEmail: '[email protected]',
options: {
service: 'Gmail',
auth: {
user: '[email protected]',
pass: 'redacted'
}
}
},
userDBs: {
defaultDBs: {
private: ['supertest']
}
}
}
CouchDB 3.1.1
SuperLogin 0.14.1
Node 14
Maybe you have an idea of what I did wrong ? Anyway thanks for maintaining this project.
config
...It works with couch but I couldn't make it work with cloudant. Is there an example?
Instead:
Is the mail server really necessary? If I am using a Provider, when and why will couch-auth send an email?
Instead, it should return a bad request and the validation errors
Currently, there is one fixed session time for every user.
It should be possible for the user to request a different, pre-configured session duration based on his request, e.g.:
The supported keys can be sent when logging in, resetting password - also when refreshing the session?
In a later iteration:
Hey @fynnlyte,
I'm facing an issue where a user login fails with an internal server error. Upon inspecting the case I found that the /auth/login
route repsonds with an error message which seems to be an upstream 409 error from CouchDB.
Here's the anonymised response I receive when trying to login with the given credentials (status 500):
{
"scope": "couch",
"statusCode": 409,
"request": {
"method": "post",
"headers": {
"content-type": "application/json",
"accept": "application/json",
"user-agent": "XXXXXX",
"Accept-Encoding": "deflate, gzip"
},
"auth": {
"username": "XXXXXX",
"password": "XXXXXX"
},
"qsStringifyOptions": {
"arrayFormat": "repeat"
},
"url": "http://localhost:5984/_users",
"paramsSerializer": {},
"data": "{\"_id\":\"org.couchdb.user:XXXXXX\",\"type\":\"user\",\"name\":\"XXXXXX\",\"user_uid\":\"XXXXXX\",\"user_id\":\"XXXXXX\",\"expires\":123456789,\"roles\":[\"XXXXXX\",],\"provider\":\"local\",\"password_scheme\":\"pbkdf2\",\"iterations\":10,\"salt\":\"XXXXXX\",\"derived_key\":\"XXXXXX\"}",
},
"errid": "non_200",
"name": "Error",
"description": "Document update conflict.",
"error": "conflict",
"reason": "Document update conflict."
}
I know the user tried to reset their password, which they said didn't work. I then reset their password to a default password using the changePassword
method. This seemed to work (got no errors), but now it seems the internal state of this users doc is broken.
Any idea of this can be fixed? Thanks a lot for your help!
Split out the core API s.t. Express doesn't need to be installed. Put that into a separate package.
Hey @LyteFM
Just wanted to say thank you for providing this maintained fork of superlogin! I still love using PouchDB/CouchDB and was running into issues when upgrading to CouchDB v3. However, your fork solved all my issues, so once again, thank you!
Best
Christoph
I am adding an Oauth provider. I was able to authenticate a user with this provider using oauth with postman. Now, I want to configure couch-auth to do it for me.
How do I create a Passport strategy? I am not using facebook, twitter, etc. I am using a very specific oauth provider. To authenticate a user, it expects a post to a specific URL with the following body:
{
"client_id":"{app registration id}",
"client_secret":"{app secret}",
"username":"{username}",
"password":"{provider's otp}",
"grant_type":"password",
"scope":"authentication_session"
}
Here, "grant_type":"password" means an "access_token" strategy.
I don't get where should I specify all these.
With 2d182fd, session caching in redis was removed in order to simplify the setup and make it compatible with Cloudant.
Since couch-auth
is now primarily targeted at self-hosted CouchDB setups and we're transitioning more and more from „offline first“ to „server first“ -> add redis as optional dependency to improve performance of checking token validity.
Maybe use dynamic imports to achieve that?
/app/node_modules/@sl-nx/superlogin-next/lib/user.js:1306
catch { }
Could it be updated to:
catch(err){}
Also type and refactor the session cleanup methods better.
cleanupExpired
should use the same functions as when removing sessions for a single user under the hood
First, thanks for all your work on this library! I've been using it to get auth working quickly with couchdb.
Second, I'm seeing an error when attempting to register a new user with 0.14.0:
(node:79787) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'user' of undefined
To reproduce:
I think the relevant parts of my config are:
local: {
// Set this to true to disable usernames and use emails instead
emailUsername: true,
},
userDBs: {
defaultDBs: {
private: ['user'],
shared: []
}
}
Then, I issue the following request: The request succeeds with 200 OK
% curl -X POST \
-d '{"email": "[email protected]", "password": "password1", "confirmPassword": "password1"}' \
-H 'Content-Type: application/json' \
http://localhost:3001/auth/register
{"success":"Request processed."}
But looking at the server logs I see the following stacktrace:
POST /auth/register 200 26.512 ms - 32
(node:79787) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'user' of undefined
at DBAuth.getDBConfig (/[path]/node_modules/@sl-nx/superlogin-next/lib/dbauth/index.js:199:101)
at /Users/asullivan/Development/spock-express/node_modules/@sl-nx/superlogin-next/lib/user.js:1001:46
at Array.forEach (<anonymous>)
at processUserDBs (/[path]/node_modules/@sl-nx/superlogin-next/lib/user.js:1000:20)
at SuperLogin.addUserDBs (/[path]/node_modules/@sl-nx/superlogin-next/lib/user.js:1018:9)
at SuperLogin.insertNewUserDocument (/[path]/node_modules/@sl-nx/superlogin-next/lib/user.js:294:30)
at /[path]/node_modules/@sl-nx/superlogin-next/lib/user.js:258:46
(node:79787) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:79787) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Do you know what this could be? I tried clearing everything in sl-users
and _users
but still no luck.
I was going through the tutorial on screen on getting started, I'm able to register and login but I'm unable to receive confirmEmail
notification, I'm using a namecheap
email to send out the emails.
I've tried adding a template for confirm email confirmEmail.njk
import express from "express";
import bodyParser from "body-parser";
import logger from "morgan";
import { SuperLogin } from "@perfood/couch-auth";
const app = express();
app.set("port", process.env.PORT || 3000);
app.use(logger("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Initialize SuperLogin
const superlogin = new SuperLogin({
dbServer: {
protocol: "http://",
host: "localhost:5984",
user: "admin",
password: "passowrd",
userDB: "sl-users",
couchAuthDB: "_users",
},
mailer: {
fromEmail: "[email protected]",
options: {
service: "email",
auth: {
user: "[email protected]",
pass: "password",
},
},
},
userDBs: {
defaultDBs: {
private: ["supertest"],
},
},
});
// Mount SuperLogin's routes to our app
app.use("/auth", superlogin.router);
app.listen(app.get("port"));
Thank you for sharing. This makes CouchDb usable! I was looking into how to add a REST "updateProfile" function so that users can update their display name, language, theme, etc...
I'll try and share what I get.
Hello,
I am having an issue, when i try to get the newly created user i am getting error 404
to repeat please follow the following steps
Package information
"@perfood/couch-auth": "^0.18.1",
"nano": "^10.0.0",
Error
Error: missing
at responseHandler (/Users/mohan/cibos-server/node_modules/nano/lib/nano.js:188:20)
at /Users/mohan/cibos-server/node_modules/nano/lib/nano.js:427:13
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
scope: 'couch',
statusCode: 404,
request: {
method: 'get',
headers: {
'content-type': 'application/json',
accept: 'application/json',
'user-agent': 'nano/10.0.0 (Node.js v16.13.0)',
'Accept-Encoding': 'deflate, gzip'
},
auth: { username: 'XXXXXX', password: 'XXXXXX' },
qsStringifyOptions: { arrayFormat: 'repeat' },
url: 'http://localhost:5984/cibos-users/506c8f93227d42aa8c827ce7a766b1c4',
params: undefined,
paramsSerializer: [Function (anonymous)],
data: undefined,
maxRedirects: 0,
httpAgent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object: null prototype],
requests: [Object: null prototype] {},
sockets: [Object: null prototype],
freeSockets: [Object: null prototype],
keepAliveMsecs: 30000,
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 3,
[Symbol(kCapture)]: false
},
httpsAgent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 443,
protocol: 'https:',
options: [Object: null prototype],
requests: [Object: null prototype] {},
sockets: [Object: null prototype] {},
freeSockets: [Object: null prototype] {},
keepAliveMsecs: 30000,
keepAlive: true,
maxSockets: 50,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 0,
maxCachedSessions: 100,
_sessionCache: [Object],
[Symbol(kCapture)]: false
}
},
headers: {
uri: 'http://localhost:5984/cibos-users/506c8f93227d42aa8c827ce7a766b1c4',
statusCode: 404,
'cache-control': 'must-revalidate',
'content-type': 'application/json',
date: 'Tue, 30 Aug 2022 11:16:35 GMT',
'x-couch-request-id': '495c245552',
'x-couchdb-body-time': '0'
},
errid: 'non_200',
description: 'missing',
error: 'not_found',
reason: 'missing'
}
I was creating some test users when I found the following behavior:
curl --request POST \
--url http://localhost:3000/auth/register \
--header 'Content-Type: application/json' \
--data '{
"email": "[email protected]",
"password": "bigsecret",
"confirmPassword": "bigsecret",
}'
curl --request POST \
--url http://localhost:3000/auth/login \
--header 'Content-Type: application/json' \
--data '{
"email": "[email protected]",
"password": "bigsecret"
}
'
{
"error": "Unauthorized",
"message": "Invalid username or password"
}
curl --request POST \
--url http://localhost:3000/auth/login \
--header 'Content-Type: application/json' \
--data '{
"email": "[email protected]",
"password": "bigsecret"
}
'
{
"issued": 1676830866748,
"expires": 1676917266748,
"provider": "local",
"token": "NlKFvdkRSh-Z4Zf-z5QmbA",
"password": "ZsO0x9N4Q6mUaOs_XHF7Jg",
"user_id": "re46jmvr",
"roles": [
"user",
"Admin",
"user"
],
"userDBs": {
"interviewer": "http://NlKFvdkRSh-Z4Zf-z5QmbA:[email protected]:5985/interviewer_d31c511c86334591bcae45d9a5b6086e"
}
}
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
files
Finally 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 the auth.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 this
...
"dependencies": {
...,
"@perfood/couch-auth": "github:ErikGoH/superlogin-next#main-keycode",
...
}
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'],
},
},
},
};
Hi, first all thanks for this updated library!
There is a bug I thing in the createUser()
method. At the end, when the method resolves with the created user, the _rev
field will only be included if it's returned by the second resolve()
(i.e. if we create a user with loginOnRegistration
set to false
)
It can lead to CouchDB update conflicts, for instance if we try to update the user doc just after creation (as we will try to insert it without the _rev
field).
// src/user.ts
// Let's say we have this.config.security.loginOnRegistration = false, and hasError = false.
return new Promise(async (resolve, reject) => {
newUser = await this.prepareNewUser(newUser);
if (hasError || !this.config.security.loginOnRegistration) {
// 1. The promise resolves. It returns newUser instead of finalUser.
resolve(hasError ? undefined : (newUser as SlUserDoc));
}
if (!hasError) {
// 2. This is executed (even if the promise has already resolved).
// The doc is inserted here, but resolve() has already been called so finalUser is not returned.
const finalUser = await this.insertNewUserDocument(newUser, req);
this.emitter.emit('signup', finalUser, 'local');
if (this.config.security.loginOnRegistration) {
resolve(finalUser);
}
}
});
Maybe we could change it like this?
this.config.security.loginOnRegistration
check, as we should return the created user no matter if it is set to true
or false
if(hasError)
return;
else {
newUser = await this.prepareNewUser(newUser);
const finalUser = await this.insertNewUserDocument(newUser, req);
this.emitter.emit('signup', finalUser, 'local');
return finalUser;
}
PS: I'm using the latest version (0.16.0)
Hi, thanks for maintaining this library! I appreciate the effort to keep this library updated constantly.
I was just wondering if there is an option to guard the register route with logged in users? Because I have a private system which does not allow public users to register or login.
We want to support template inheritance and i18n. Nunjucks seems to be a great choice for that.
Hello,
I was trying to integrate the nodemailer-ses-transport to send the email but it is throwing me the following error
my configuration is as follows
`
const sesTransporter = require('nodemailer-ses-transport');
mailer: {
fromEmail: '[email protected]',
transport: sesTransporter,
provider: 'ses',
options: {
accessKeyId: 'access key',
secretAccessKey: 'secret access key',
region: 'region',
bucket: 'bucket',
},
}
`
I am using node version 16.
See https://github.com/perfood/couch-auth/blob/master/src/template-utils.ts#L11
Hi,
I think that in the typings the type of SlLoginSession.profile
should be any
instead of string
. SlUserDoc.profile
is of type any
(which I think is correct), and SlLoginSession.profile
is copied from SlUserDoc.profile
in User.createSession()
, so it should have the same type.
Can I install it over npm like the main repo 'npm install superlogin'
or must I clone this git?
Can you please give a small tutorial on how to install?
Thanks
allow to configure to set up DBs with default admin permission, if they are not present https://github.com/perfood/couch-auth/blob/master/src/types/config.ts -> extend config.
allow to provide design docs that will be seeded to these DBs -> https://github.com/perfood/couch-auth/blob/master/src/index.ts#L69 do the setup before seed
If CouchDB or the express server crashes in the middle of processing a login request, a session token might already be generated but that token is not yet documented within sl-users
. This leads to errors as:
Could not create session token with key: hgsi2BLWQleolfmw3JmscA - was inactiveSessions copied and does the key already exist?
Document update conflict.
Such conflicts should be resolved automatically. In case of a conflict error when creating the entry in _users
:
Within the token validity, the route should just return OK and state that the E-Mail is successfully confirmed. This should be configurable via a config option and be turned off by default.
I have a few special users in my _users db that weren't created through couch-auth. For example, special-purpose administrative users and a "public" user that can make simple requests to couch via Basic authentication without creating a session. I'd like them to stick around. But any endpoint protected by the requireAuth middleware can be used to delete these users. A basic example:
//endpoint expecting an Authorization: Bearer header validating a couch-auth user
router.get('/protected', couchAuth.requireAuth, function(req, res, next) {
res.send('This endpoint is protected!');
})
A request of the form
curl -X GET http://localhost:3000/api/protected -H 'Authorization: Bearer public:madeUpPassword'
will delete the user named 'public' from _users.
The requireAuth middleware checks that the document in _users identified by the first part of the Bearer credentials is actually a session for a couch-auth user instead of a "normal" couchdb user, and only removes the former. Possibly through the presence of fields like 'user_uid', 'user_id', 'expires', etc.
Users occasionally want to change their email into an address with which they have already registered an account.
In that case, the email change requests indicates a success (because we don't allow account guessing) but nothing actually happens. The user is left in the dark.
Possible solution: Similar to the handling of the registration flow, send out an informational email that there is already an account associated with that email to the new email only. This way, the user can be informed that this account would need to be deleted before they can change into the mail.
If createUser() in user.ts is called (in my case via the /register endpoint), and config.local.sendConfirmEmail
is true, and your SMTP credentials are messed up (due to incorrect credentials, some other configuration error, creds being revoked, etc), nodeMailer will throw an exception which doesn't seem to be caught properly.
The promise returned by createUser() actually resolves successfully, the user is added to sl-users, and the /register route does call this line (routes.ts:153):
res.status(200).json({ success: 'Request processed.' });
But after this is executed, the async call to send the confirmation email runs, at insertNewUserDocument() (user.ts:475). My console prints this error
/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:787
err = new Error(message);
^
Error: Invalid login: 535 Authentication failed
at SMTPConnection._formatError (/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:787:19)
at SMTPConnection._actionAUTHComplete (/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:1539:34)
at SMTPConnection.<anonymous> (/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:543:26)
at SMTPConnection._processResponse (/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:950:20)
at SMTPConnection._onData (/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:752:14)
at TLSSocket.SMTPConnection._onSocketData (/usr/src/app/node_modules/@perfood/couch-auth/node_modules/nodemailer/lib/smtp-connection/index.js:191:44)
at TLSSocket.emit (node:events:513:28)
at addChunk (node:internal/streams/readable:315:12)
at readableAddChunk (node:internal/streams/readable:289:9)
at TLSSocket.Readable.push (node:internal/streams/readable:228:10) {
code: 'EAUTH',
response: '535 Authentication failed',
responseCode: 535,
command: 'AUTH PLAIN'
}
and express hangs since it's not handled. It doesn't matter if you set config.security.forwardErrors
.
The problematic code in the return statement of createUser():
return new Promise(async (resolve, reject) => {
newUser = await this.prepareNewUser(newUser);
if (hasError || !this.config.security.loginOnRegistration) {
resolve(hasError ? undefined : (newUser as SlUserDoc));
}
if (!hasError) {
const finalUser = await this.insertNewUserDocument(newUser, req);
this.emitter.emit('signup', finalUser, 'local');
if (this.config.security.loginOnRegistration) {
resolve(finalUser);
}
}
});
It's "fixed", as in it doesn't hang express, if I wrap const finalUser = await this.insertNewUserDocument(newUser, req);
in try/catch. But the async function inside the promise constructor looks like an instance of the Promise constructor anti-pattern. So you may want to rework that part.
I'm not sure if you want createUser() to reject when there's a problem sending the confirmation email; after all, the user WAS created, it's just that the confirmation email didn't go out. Basically createUser() in this case is a two-part non-atomic operation, so do you:
2 is more atomic and less work for me. But people who don't have config.local.requireEmailConfirm
might prefer approach 1.
MailConfig
probably isn't quite correct -> fixed.Use nano
by default to reduce dependencies, but allow passing a cloudant
- instance instead for IAM compatibility.
Or just discard cloudant
completely now that it won't be supported anymore. It's still possible to use IBM Cloudant via legacy auth then.
Docs must be adjusted accordingly.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.