Skip to content

Commit

Permalink
feat: Remove console auth and require dashboard accessKey for api calls
Browse files Browse the repository at this point in the history
  • Loading branch information
Mmarzex committed Sep 19, 2023
1 parent a3968e1 commit 9c17857
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 341 deletions.
52 changes: 21 additions & 31 deletions api-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ const fetch = require('node-fetch');
const log = require('./log').log.get('api');
const ServerlessError = require('./serverless-error');
const urls = require('./lib/auth/urls');
const resolveAuthToken = require('./auth/resolve-token');
const resolveAuthMethod = require('./auth/resolve-mode');

let requestIdCounter = 0;

Expand All @@ -17,13 +15,15 @@ module.exports = async (pathname, options = {}) => {
if (!isObject(options)) options = {};
const method = ensureString(options.method, { name: 'options.method', default: 'GET' });
const body = ensureObject(options.body, { name: 'options.body', isOptional: true });
const authMethod = options.noAuth ? 'none' : options.authMethod || (await resolveAuthMethod());
if (!authMethod) throw new Error('Not authenticated to send request to the Console server');
const requestId = ++requestIdCounter;
let authorization = {};
if (!options.noAuth && !options.accessKey) {
authorization = { Authorization: `Bearer ${await resolveAuthToken()}` };
} else if (!options.noAuth && options.accessKey) {
if (!options.accessKey && !options.noAuth) {
throw new ServerlessError(
'An access key must be specified. Please try logging out and logging back in',
'DASHBOARD_ACCESS_KEY_MISSING'
);
}
if (options.accessKey && !options.noAuth) {
authorization = { Authorization: `Bearer ${options.accessKey}` };
}

Expand All @@ -33,8 +33,6 @@ module.exports = async (pathname, options = {}) => {
...authorization,
'Content-Type': 'application/json',
};
if (authMethod === 'org') headers['sls-token-type'] = 'orgToken';
if (authMethod === 'dashboard') headers['sls-token-type'] = 'dashboardToken';
const fetchOptions = {
method,
headers,
Expand All @@ -46,8 +44,8 @@ module.exports = async (pathname, options = {}) => {
} catch (error) {
log.debug('Server unavailable', error);
throw new ServerlessError(
'Console server is not available, please try again later',
'CONSOLE_SERVER_UNAVAILABLE'
'Dashboard server is not available, please try again later',
'DASHBOARD_SERVER_UNAVAILABLE'
);
}
})();
Expand All @@ -57,33 +55,25 @@ module.exports = async (pathname, options = {}) => {
log.debug('[%d] %s', requestId, responseText);
if (response.status < 500) {
if (response.status === 401) {
if (authMethod === 'org') {
throw Object.assign(
new ServerlessError(
'Unauthorized request: Either org token is invalid, ' +
'or org token is not supported for this command ' +
'(run the command as logged-in user instead)',
'CONSOLE_ORG_AUTH_REJECTED'
),
{ httpStatusCode: 401 }
);
}
throw Object.assign(
new ServerlessError(
'Unauthorized request: Run "sls login --console" to authenticate',
'CONSOLE_USER_AUTH_REJECTED'
'Unauthorized request: Run "sls login to authenticate',
'DASHBOARD_USER_AUTH_REJECTED'
),
{ httpStatusCode: 401 }
);
}
throw Object.assign(new Error(`Console server error: [${response.status}] ${responseText}`), {
code: `CONSOLE_SERVER_ERROR_${response.status}`,
httpStatusCode: response.status,
});
throw Object.assign(
new Error(`Dashboard server error: [${response.status}] ${responseText}`),
{
code: `DASHBOARD_SERVER_ERROR_${response.status}`,
httpStatusCode: response.status,
}
);
}
throw new ServerlessError(
'Console server is unavailable, please try again later',
'CONSOLE_SERVER_REQUEST_FAILED'
'Dashboard server is unavailable, please try again later',
'DASHBOARD_SERVER_REQUEST_FAILED'
);
}
if ((response.headers.get('content-type') || '').includes('application/json')) {
Expand All @@ -93,7 +83,7 @@ module.exports = async (pathname, options = {}) => {
} catch (error) {
const responseText = await response.text();
log.debug('[%d] %s', requestId, responseText);
throw new Error(`Console server error: received unexpected response: ${responseText}`);
throw new Error(`Dashboard server error: received unexpected response: ${responseText}`);
}
})();
log.debug('[%d] %o', requestId, responseData);
Expand Down
61 changes: 27 additions & 34 deletions test/api-request.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ describe('test/api-request.test.js', () => {
let lastMethod;
let lastRequestHeaders;
let lastRequestBody;
let authMode = 'user';
const testAccessKey = 'abc123Key';
beforeEach(() => {
const responseHeaders = new Map([['content-type', 'application/json; charset=utf-8']]);
api = requireUncached(() =>
proxyquire('../api-request', {
'./auth/resolve-token': async () => 'token',
'./auth/resolve-mode': async () => authMode,
'node-fetch': sinon
.stub()
.callsFake(async (url, { method, headers: requestHeaders, body } = { method: 'GET' }) => {
Expand Down Expand Up @@ -100,17 +98,16 @@ describe('test/api-request.test.js', () => {
})
);
});
afterEach(() => {
authMode = 'user';
});

it('should handle success response', async () => {
expect(await api('/success/')).to.deep.equal({ foo: 'bar' });
expect(await api('/success/', { accessKey: testAccessKey })).to.deep.equal({ foo: 'bar' });
expect(lastMethod).to.equal('GET');
});

it('should handle post requests', async () => {
expect(await api('/submission/', { method: 'POST', body: { foo: 'bar' } })).to.deep.equal({
expect(
await api('/submission/', { method: 'POST', body: { foo: 'bar' }, accessKey: testAccessKey })
).to.deep.equal({
foo: 'bar',
});
expect(lastMethod).to.equal('POST');
Expand All @@ -119,7 +116,13 @@ describe('test/api-request.test.js', () => {
});

it('should support body array input', async () => {
expect(await api('/submission/', { method: 'POST', body: [{ foo: 'bar' }] })).to.deep.equal({
expect(
await api('/submission/', {
method: 'POST',
body: [{ foo: 'bar' }],
accessKey: testAccessKey,
})
).to.deep.equal({
foo: 'bar',
});
expect(lastMethod).to.equal('POST');
Expand All @@ -133,36 +136,26 @@ describe('test/api-request.test.js', () => {
});

it('should handle server unavailability', async () =>
expect(api('/server-unavailable/')).to.eventually.be.rejected.and.have.property(
'code',
'CONSOLE_SERVER_UNAVAILABLE'
));
expect(
api('/server-unavailable/', { accessKey: testAccessKey })
).to.eventually.be.rejected.and.have.property('code', 'DASHBOARD_SERVER_UNAVAILABLE'));

it('should handle server error', async () =>
expect(api('/server-error/')).to.eventually.be.rejected.and.have.property(
'code',
'CONSOLE_SERVER_REQUEST_FAILED'
));
expect(
api('/server-error/', { accessKey: testAccessKey })
).to.eventually.be.rejected.and.have.property('code', 'DASHBOARD_SERVER_REQUEST_FAILED'));

it('should handle programmer error', async () =>
expect(api('/programmer-error/')).to.eventually.be.rejected.and.have.property(
'code',
'CONSOLE_SERVER_ERROR_400'
));

it('should handle org auth error', async () => {
authMode = 'org';
await expect(api('/org-auth-error/')).to.eventually.be.rejected.and.have.property(
'code',
'CONSOLE_ORG_AUTH_REJECTED'
);
});
expect(
api('/programmer-error/', { accessKey: testAccessKey })
).to.eventually.be.rejected.and.have.property('code', 'DASHBOARD_SERVER_ERROR_400'));

it('should handle user auth error', async () =>
expect(api('/user-auth-error/')).to.eventually.be.rejected.and.have.property(
'code',
'CONSOLE_USER_AUTH_REJECTED'
));
expect(
api('/user-auth-error/', { accessKey: testAccessKey })
).to.eventually.be.rejected.and.have.property('code', 'DASHBOARD_USER_AUTH_REJECTED'));
it('should handle unexpected response', async () =>
expect(api('/unexpected-response/')).to.eventually.be.rejectedWith('Unexpected response'));
expect(
api('/unexpected-response/', { accessKey: testAccessKey })
).to.eventually.be.rejectedWith('Unexpected response'));
});
70 changes: 0 additions & 70 deletions test/auth/login.test.js

This file was deleted.

73 changes: 0 additions & 73 deletions test/auth/logout.test.js

This file was deleted.

41 changes: 0 additions & 41 deletions test/auth/resolve-mode.test.js

This file was deleted.

0 comments on commit 9c17857

Please sign in to comment.