Skip to content

Commit

Permalink
fix: Gracefully handling EACCES error when starting MFA server
Browse files Browse the repository at this point in the history
Fixes #343
  • Loading branch information
Frank Steiler committed Sep 22, 2023
1 parent 8be7b52 commit 2fc2bcb
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 5 deletions.
4 changes: 4 additions & 0 deletions app/src/app/error/codes/mfa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export const ADDR_IN_USE_ERR: ErrorStruct = buildErrorStruct(
name, prefix, `ADDR_IN_USE`, `HTTP Server could not start, because address/port is in use`,
);

export const INSUFFICIENT_PRIVILEGES: ErrorStruct = buildErrorStruct(
name, prefix, `ADDR_IN_USE`, `HTTP Server could not start, because user has insufficient privileges to open address/port`,
);

export const SUBMIT_FAILED: ErrorStruct = buildErrorStruct(
name, prefix, `SUBMIT_FAILED`, `Unable to submit MFA code`,
);
Expand Down
1 change: 1 addition & 0 deletions app/src/app/event/error-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const reportDenyList = [
ERR_SIGINT.code,
ERR_SIGTERM.code,
MFA_ERR.ADDR_IN_USE_ERR.code, // Only happens if port/address is in use
MFA_ERR.INSUFFICIENT_PRIVILEGES.code, // Only happens if user is lacking privileges to open port/address
MFA_ERR.SERVER_TIMEOUT.code, // Only happens if user does not interact within 10 minutes
LIBRARY_ERR.LOCKED.code, // Only happens if library is locked
AUTH_ERR.UNAUTHORIZED.code, // Only happens if username/password don't match
Expand Down
14 changes: 11 additions & 3 deletions app/src/lib/icloud/mfa/mfa-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,17 @@ export class MFAServer {
Resources.logger(this).debug(`Preparing MFA server on port ${Resources.manager().mfaServerPort}`);
this.server = http.createServer(this.handleRequest.bind(this));
this.server.on(`error`, err => {
const icpsErr = (Object.hasOwn(err, `code`) && (err as any).code === `EADDRINUSE`)
? new iCPSError(MFA_ERR.ADDR_IN_USE_ERR).addContext(`port`, Resources.manager().mfaServerPort)
: new iCPSError(MFA_ERR.SERVER_ERR);
let icpsErr = new iCPSError(MFA_ERR.SERVER_ERR);

if (Object.hasOwn(err, `code`)) {
if ((err as any).code === `EADDRINUSE`) {
icpsErr = new iCPSError(MFA_ERR.ADDR_IN_USE_ERR).addContext(`port`, Resources.manager().mfaServerPort);
}

if ((err as any).code === `EACCES`) {
icpsErr = new iCPSError(MFA_ERR.INSUFFICIENT_PRIVILEGES).addContext(`port`, Resources.manager().mfaServerPort);
}
}

icpsErr.addCause(err);

Expand Down
13 changes: 11 additions & 2 deletions app/test/unit/icloud.mfa-server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,18 @@ describe(`Server lifecycle`, () => {
const errorEvent = mockedEventManager.spyOnEvent(iCPSEventMFA.ERROR);
const error = new Error(`Address in use`);
(error as any).code = `EADDRINUSE`;
server.server.emit(`error`, new Error(`Address in use`));
server.server.emit(`error`, error);

expect(errorEvent).toHaveBeenCalledWith(new Error(`HTTP Server Error`));
expect(errorEvent).toHaveBeenCalledWith(new iCPSError(MFA_ERR.ADDR_IN_USE_ERR));
});

test(`Handle EACCES error`, () => {
const errorEvent = mockedEventManager.spyOnEvent(iCPSEventMFA.ERROR);
const error = new Error(`No privileges`);
(error as any).code = `EACCES`;
server.server.emit(`error`, error);

expect(errorEvent).toHaveBeenCalledWith(new iCPSError(MFA_ERR.INSUFFICIENT_PRIVILEGES));
});

test(`Handle MFA timeout`, () => {
Expand Down

0 comments on commit 2fc2bcb

Please sign in to comment.