diff --git a/lib/tasks/import/api.js b/lib/tasks/import/api.js index 3b5d8095f..e93be173a 100644 --- a/lib/tasks/import/api.js +++ b/lib/tasks/import/api.js @@ -39,53 +39,81 @@ async function setup(version, url, data) { await got.post('/authentication/setup/', {baseUrl, body, json: true}); } +function handleError(error) { + const {response} = error; + if (response.statusCode === 404) { + throw new SystemError({ + message: 'There is no user with that email address.', + err: error + }); + } + + if (response.statusCode === 422) { + throw new SystemError({ + message: 'Your password is incorrect.', + err: error + }); + } + + throw error; +} + async function getAuthOpts(version, url, {username, password}) { const baseUrl = getBaseUrl(version, url); if (semver.major(version) === 1) { const {body: configBody} = await got('/configuration/', {baseUrl, json: true}); const {clientId, clientSecret} = get(configBody, 'configuration[0]', {}); - const {body: authBody} = await got.post('/authentication/token/', { + + try { + const {body: authBody} = await got.post('/authentication/token/', { + baseUrl, + json: true, + form: true, + body: { + grant_type: 'password', + client_id: clientId, + client_secret: clientSecret, + username, + password + } + }); + + return { + baseUrl, + headers: { + Authorization: `Bearer ${authBody.access_token}` + } + }; + } catch (error) { + handleError(error); + } + } + + try { + const {headers} = await got.post('/session/', { baseUrl, - json: true, - form: true, - body: { - grant_type: 'password', - client_id: clientId, - client_secret: clientSecret, - username, - password - } + headers: { + Origin: url, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({username, password}) }); + /* istanbul ignore next */ + const cookies = headers['set-cookie'] || []; + const filteredCookies = cookies.map(Cookie.parse).filter(Boolean).map(c => c.cookieString()); + return { baseUrl, headers: { - Authorization: `Bearer ${authBody.access_token}` + Origin: url, + Cookie: filteredCookies } }; + } catch (error) { + handleError(error); } - - const {headers} = await got.post('/session/', { - baseUrl, - headers: { - Origin: url, - 'Content-Type': 'application/json' - }, - body: JSON.stringify({username, password}) - }); - - /* istanbul ignore next */ - const cookies = headers['set-cookie'] || []; - const filteredCookies = cookies.map(Cookie.parse).filter(Boolean).map(c => c.cookieString()); - - return { - baseUrl, - headers: { - Origin: url, - Cookie: filteredCookies - } - }; } async function runImport(version, url, auth, exportFile) { diff --git a/test/unit/tasks/import/api-spec.js b/test/unit/tasks/import/api-spec.js index 632f541e7..7a371ca32 100644 --- a/test/unit/tasks/import/api-spec.js +++ b/test/unit/tasks/import/api-spec.js @@ -111,6 +111,54 @@ describe('Unit > Tasks > Import > setup', function () { expect(importScope.isDone()).to.be.true; }); + it('handles 404 auth error', async function () { + const clientId = 'client-id'; + const clientSecret = 'client-secret'; + const configBody = { + configuration: [{ + clientId, clientSecret + }] + }; + + const tokenRequestBody = { + grant_type: 'password', + client_id: clientId, + client_secret: clientSecret, + username: 'test@example.com', + password: 'password' + }; + + const configScope = nock(testUrl) + .get('/ghost/api/v0.1/configuration/') + .reply(200, configBody); + + const tokenScope = nock(testUrl) + .post('/ghost/api/v0.1/authentication/token/', tokenRequestBody) + .reply(404, {}); + + const importScope = nock(testUrl, { + reqheaders: { + Authorization: 'Bearer access-token' + } + }).post('/ghost/api/v0.1/db/').reply(200, {}); + + try { + await runImport('1.0.0', testUrl, { + username: 'test@example.com', + password: 'password' + }, path.join(__dirname, 'fixtures/0.11.x.json')); + } catch (error) { + expect(error).to.be.an.instanceof(SystemError); + expect(error.message).to.equal('There is no user with that email address.'); + expect(configScope.isDone()).to.be.true; + expect(tokenScope.isDone()).to.be.true; + expect(importScope.isDone()).to.be.false; + return; + } + + expect.fail('runImport should have errored'); + }); + it('2.x', async function () { const sessionScope = nock(testUrl, { reqheaders: { @@ -141,6 +189,41 @@ describe('Unit > Tasks > Import > setup', function () { expect(importScope.isDone()).to.be.true; }); + it('handles 422 auth error', async function () { + const sessionScope = nock(testUrl, { + reqheaders: { + Origin: testUrl + } + }).post('/ghost/api/v2/admin/session/', { + username: 'test@example.com', + password: 'password' + }).reply(422, 'Error'); + + const importScope = nock(testUrl, { + reqheaders: { + cookie: [ + 'ghost-admin-api-session=test-session-data' + ], + origin: testUrl + } + }).post('/ghost/api/v2/admin/db/').reply(201, {}); + + try { + await runImport('2.0.0', 'http://localhost:2368', { + username: 'test@example.com', + password: 'password' + }, path.join(__dirname, 'fixtures/2.x.json')); + } catch (error) { + expect(error).to.be.an.instanceof(SystemError); + expect(error.message).to.equal('Your password is incorrect.'); + expect(sessionScope.isDone()).to.be.true; + expect(importScope.isDone()).to.be.false; + return; + } + + expect.fail('runImport should have errored'); + }); + it('3.x', async function () { const sessionScope = nock(testUrl, { reqheaders: { @@ -170,6 +253,41 @@ describe('Unit > Tasks > Import > setup', function () { expect(sessionScope.isDone()).to.be.true; expect(importScope.isDone()).to.be.true; }); + + it('rethrows non-auth errors', async function () { + const sessionScope = nock(testUrl, { + reqheaders: { + Origin: testUrl + } + }).post('/ghost/api/v3/admin/session/', { + username: 'test@example.com', + password: 'password' + }).reply(500, 'Error'); + + const importScope = nock(testUrl, { + reqheaders: { + cookie: [ + 'ghost-admin-api-session=test-session-data' + ], + origin: testUrl + } + }).post('/ghost/api/v3/admin/db/').reply(201, {}); + + try { + await runImport('3.0.0', 'http://localhost:2368', { + username: 'test@example.com', + password: 'password' + }, path.join(__dirname, 'fixtures/3.x.json')); + } catch (error) { + expect(error.response).to.exist; + expect(error.response.statusCode).to.equal(500); + expect(sessionScope.isDone()).to.be.true; + expect(importScope.isDone()).to.be.false; + return; + } + + expect.fail('runImport should have errored'); + }); }); describe('downloadExport', function () {