Skip to content

Commit bc35517

Browse files
authored
Merge pull request #1775 from nodeSolidServer/fix/issue#1774
fix issue 1774 & 1770
2 parents 88d3a86 + f669e5c commit bc35517

File tree

4 files changed

+56
-9
lines changed

4 files changed

+56
-9
lines changed

default-views/auth/reset-link-sent.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</div>
1515

1616
<div class="alert alert-success">
17-
<p>A Reset Password link has been sent to your email.</p>
17+
<p>A Reset Password link has been sent from the associated email account.</p>
1818
</div>
1919
</div>
2020
</body>

lib/models/account-manager.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ class AccountManager {
537537
throw new Error('Email service is not set up')
538538
}
539539

540-
if (!userAccount.email) {
540+
if (userAccount && !userAccount.email) {
541541
throw new Error('Account recovery email has not been provided')
542542
}
543543
}

lib/requests/password-reset-email-request.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class PasswordResetEmailRequest extends AuthRequest {
9494
.then(() => request.validate())
9595
.then(() => request.loadUser())
9696
.then(userAccount => request.sendResetLink(userAccount))
97-
.then(() => request.renderSuccess())
97+
.then(() => request.resetLinkMessage())
9898
.catch(error => request.error(error))
9999
}
100100

@@ -123,7 +123,10 @@ class PasswordResetEmailRequest extends AuthRequest {
123123
return this.accountManager.accountExists(username)
124124
.then(exists => {
125125
if (!exists) {
126-
throw new Error('Account not found for that username')
126+
// For security reason avoid leaking error information
127+
// See: https://github.com/nodeSolidServer/node-solid-server/issues/1770
128+
this.accountManager.verifyEmailDependencies()
129+
return this.resetLinkMessage()
127130
}
128131

129132
const userData = { username }
@@ -191,7 +194,7 @@ class PasswordResetEmailRequest extends AuthRequest {
191194
/**
192195
* Displays the 'your reset link has been sent' success message view
193196
*/
194-
renderSuccess () {
197+
resetLinkMessage () {
195198
this.response.render('auth/reset-link-sent')
196199
}
197200
}

test/unit/password-reset-email-request-test.js

+48-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const HttpMocks = require('node-mocks-http')
1414
const PasswordResetEmailRequest = require('../../lib/requests/password-reset-email-request')
1515
const AccountManager = require('../../lib/models/account-manager')
1616
const SolidHost = require('../../lib/models/solid-host')
17+
const EmailService = require('../../lib/services/email-service')
1718

1819
describe('PasswordResetEmailRequest', () => {
1920
describe('constructor()', () => {
@@ -153,6 +154,39 @@ describe('PasswordResetEmailRequest', () => {
153154
expect(request.error).to.not.have.been.called()
154155
})
155156
})
157+
158+
it('should hande a reset request with no username without privacy leakage', () => {
159+
const host = SolidHost.from({ serverUri: 'https://example.com' })
160+
const store = { suffixAcl: '.acl' }
161+
const accountManager = AccountManager.from({ host, multiuser: true, store })
162+
accountManager.loadAccountRecoveryEmail = sinon.stub().resolves('[email protected]')
163+
accountManager.sendPasswordResetEmail = sinon.stub().resolves()
164+
accountManager.accountExists = sinon.stub().resolves(false)
165+
166+
const returnToUrl = 'https://example.com/resource'
167+
const username = 'alice'
168+
const response = HttpMocks.createResponse()
169+
response.render = sinon.stub()
170+
171+
const options = { accountManager, username, returnToUrl, response }
172+
const request = new PasswordResetEmailRequest(options)
173+
174+
sinon.spy(request, 'error')
175+
sinon.spy(request, 'validate')
176+
sinon.spy(request, 'loadUser')
177+
178+
return PasswordResetEmailRequest.handlePost(request)
179+
.then(() => {
180+
expect(request.validate).to.have.been.called()
181+
expect(request.loadUser).to.have.been.called()
182+
expect(request.loadUser).to.throw()
183+
}).catch(() => {
184+
expect(request.error).to.have.been.called()
185+
expect(response.render).to.have.been.calledWith('auth/reset-link-sent')
186+
expect(accountManager.loadAccountRecoveryEmail).to.not.have.been.called()
187+
expect(accountManager.sendPasswordResetEmail).to.not.have.been.called()
188+
})
189+
})
156190
})
157191

158192
describe('loadUser()', () => {
@@ -175,16 +209,26 @@ describe('PasswordResetEmailRequest', () => {
175209
it('should throw an error if the user does not exist', done => {
176210
const host = SolidHost.from({ serverUri: 'https://example.com' })
177211
const store = { suffixAcl: '.acl' }
178-
const accountManager = AccountManager.from({ host, multiuser: true, store })
212+
const emailService = sinon.stub().returns(EmailService)
213+
const accountManager = AccountManager.from({ host, multiuser: true, store, emailService })
179214
accountManager.accountExists = sinon.stub().resolves(false)
180215
const username = 'alice'
181-
182216
const options = { accountManager, username }
183217
const request = new PasswordResetEmailRequest(options)
184218

219+
sinon.spy(request, 'resetLinkMessage')
220+
sinon.spy(accountManager, 'userAccountFrom')
221+
sinon.spy(accountManager, 'verifyEmailDependencies')
222+
185223
request.loadUser()
186-
.catch(error => {
187-
expect(error.message).to.equal('Account not found for that username')
224+
.then(() => {
225+
expect(accountManager.userAccountFrom).to.have.been.called()
226+
expect(accountManager.verifyEmailDependencies).to.have.been.called()
227+
expect(accountManager.verifyEmailDependencies).to.throw()
228+
done()
229+
})
230+
.catch(() => {
231+
expect(request.resetLinkMessage).to.have.been.called()
188232
done()
189233
})
190234
})

0 commit comments

Comments
 (0)