diff --git a/src/apps.js b/src/apps.js index d64b9f4a4..25e60bfe6 100644 --- a/src/apps.js +++ b/src/apps.js @@ -1474,8 +1474,6 @@ async function install(data, auditSource) { if (addError && addError.reason === BoxError.ALREADY_EXISTS) throw getDuplicateErrorDetails(addError.message, locations, portBindings); if (addError) throw addError; - await purchaseApp({ appId, appstoreId: appStoreId, manifestId: manifest.id || 'customapp' }); - const task = { args: { restoreConfig: null, skipDnsSetup, overwriteDns }, values: { }, @@ -2376,17 +2374,6 @@ async function exportApp(app, data, auditSource) { return { taskId }; } -async function purchaseApp(data) { - assert.strictEqual(typeof data, 'object'); - - const [purchaseError] = await safe(appstore.purchaseApp(data)); - if (!purchaseError) return; - - await del(data.appId); - - throw purchaseError; -} - async function clone(app, data, user, auditSource) { assert.strictEqual(typeof app, 'object'); assert.strictEqual(typeof data, 'object'); @@ -2458,8 +2445,6 @@ async function clone(app, data, user, auditSource) { if (addError && addError.reason === BoxError.ALREADY_EXISTS) throw getDuplicateErrorDetails(addError.message, locations, portBindings); if (addError) throw addError; - await purchaseApp({ appId: newAppId, appstoreId: app.appStoreId, manifestId: manifest.id || 'customapp' }); - const restoreConfig = { remotePath: backupInfo.remotePath, backupFormat: backupInfo.format }; const task = { args: { restoreConfig, overwriteDns, skipDnsSetup, oldManifest: null }, @@ -2535,8 +2520,6 @@ async function unarchive(archive, data, auditSource) { if (addError && addError.reason === BoxError.ALREADY_EXISTS) throw getDuplicateErrorDetails(addError.message, locations, portBindings); if (addError) throw addError; - await purchaseApp({ appId, appstoreId: appStoreId, manifestId: manifest.id || 'customapp' }); - const task = { args: { restoreConfig, overwriteDns }, values: {}, @@ -2564,8 +2547,6 @@ async function uninstall(app, auditSource) { const error = checkAppState(app, exports.ISTATE_PENDING_UNINSTALL); if (error) throw error; - await appstore.unpurchaseApp(appId, { appstoreId: app.appStoreId, manifestId: app.manifest.id || 'customapp' }); - const task = { args: {}, values: {}, diff --git a/src/appstore.js b/src/appstore.js index 52816ffe2..77caff4eb 100644 --- a/src/appstore.js +++ b/src/appstore.js @@ -18,9 +18,6 @@ exports = module.exports = { registerCloudronWithLogin, updateCloudron, - purchaseApp, - unpurchaseApp, - getSubscription, isFreePlan, @@ -171,60 +168,6 @@ function isFreePlan(subscription) { return !subscription || subscription.plan.id === 'free'; } -// See app.js install it will create a db record first but remove it again if appstore purchase fails -async function purchaseApp(data) { - assert.strictEqual(typeof data, 'object'); // { appstoreId, manifestId, appId } - assert(data.appstoreId || data.manifestId); - assert.strictEqual(typeof data.appId, 'string'); - - const token = await settings.get(settings.APPSTORE_API_TOKEN_KEY); - if (!token) throw new BoxError(BoxError.LICENSE_ERROR, 'Missing token'); - - const [error, response] = await safe(superagent.post(`${await getApiServerOrigin()}/api/v1/cloudronapps`) - .send(data) - .query({ accessToken: token }) - .timeout(60 * 1000) - .ok(() => true)); - - if (error) throw new BoxError(BoxError.NETWORK_ERROR, error); - if (response.status === 404) throw new BoxError(BoxError.NOT_FOUND, 'appstoreId does not exist'); - if (response.status === 401) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid appstore token'); - if (response.status === 402) throw new BoxError(BoxError.LICENSE_ERROR, response.body.message); - // 200 if already purchased, 201 is newly purchased - if (response.status !== 201 && response.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `App purchase failed. ${response.status} ${JSON.stringify(response.body)}`); -} - -async function unpurchaseApp(appId, data) { - assert.strictEqual(typeof appId, 'string'); - assert.strictEqual(typeof data, 'object'); // { appstoreId, manifestId } - assert(data.appstoreId || data.manifestId); - - const token = await settings.get(settings.APPSTORE_API_TOKEN_KEY); - if (!token) throw new BoxError(BoxError.LICENSE_ERROR, 'Missing token'); - - const url = `${await getApiServerOrigin()}/api/v1/cloudronapps/${appId}`; - - let [error, response] = await safe(superagent.get(url) - .query({ accessToken: token }) - .timeout(60 * 1000) - .ok(() => true)); - - if (error) throw new BoxError(BoxError.NETWORK_ERROR, error); - if (response.status === 404) return; // was never purchased - if (response.status === 401) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid appstore token'); - if (response.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `App unpurchase failed to get app. status:${response.status}`); - - [error, response] = await safe(superagent.del(url) - .send(data) - .query({ accessToken: token }) - .timeout(60 * 1000) - .ok(() => true)); - - if (error) throw new BoxError(BoxError.NETWORK_ERROR, error); - if (response.status === 401) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid appstore token'); - if (response.status !== 204) throw new BoxError(BoxError.EXTERNAL_ERROR, `App unpurchase failed. status:${response.status}`); -} - async function getBoxUpdate(options) { assert.strictEqual(typeof options, 'object'); @@ -327,11 +270,6 @@ async function registerCloudron3(domain, version) { await settings.set(settings.APPSTORE_API_TOKEN_KEY, response.body.token); debug(`registerCloudron: Cloudron registered with id ${response.body.id}`); - - // // app could already have been installed if we deleted the cloudron.io record and user re-registers - // for (const app of await apps.list()) { - // await safe(purchaseApp({ appId: app.id, appstoreId: app.appStoreId, manifestId: app.manifest.id || 'customapp' }), { debug }); - // } } async function registerCloudron(data) { @@ -355,11 +293,6 @@ async function registerCloudron(data) { await settings.set(settings.APPSTORE_API_TOKEN_KEY, response.body.cloudronToken); debug(`registerCloudron: Cloudron registered with id ${response.body.cloudronId}`); - - // app could already have been installed if we deleted the cloudron.io record and user re-registers - for (const app of await apps.list()) { - await safe(purchaseApp({ appId: app.id, appstoreId: app.appStoreId, manifestId: app.manifest.id || 'customapp' }), { debug }); - } } async function updateCloudron(data) { diff --git a/src/routes/test/apps-test.js b/src/routes/test/apps-test.js index a0d473977..930320053 100644 --- a/src/routes/test/apps-test.js +++ b/src/routes/test/apps-test.js @@ -396,22 +396,8 @@ xdescribe('App API', function () { }); }); - it('app install fails due to purchase failure', function (done) { - const fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/test').reply(200, { manifest: APP_MANIFEST }); - - superagent.post(SERVER_URL + '/api/v1/apps') - .query({ access_token: token }) - .send({ appStoreId: APP_STORE_ID, subdomain: APP_SUBDOMAIN, domain: DOMAIN_0.domain, portBindings: null, accessRestriction: null }) - .end(function (err, res) { - expect(res.status).to.equal(402); - expect(fake1.isDone()).to.be.ok(); - done(); - }); - }); - - it('app install succeeds with purchase', async function () { + it('app install succeeds', async function () { const fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST }); - const fake2 = nock(settings.apiServerOrigin()).post(function (uri) { return uri.indexOf('/api/v1/cloudronapps') >= 0; }, (body) => body.appstoreId === APP_STORE_ID && body.manifestId === APP_MANIFEST.id && body.appId).reply(201, { }); await settings.setAppstoreApiToken(USER_1_APPSTORE_TOKEN); @@ -423,7 +409,6 @@ xdescribe('App API', function () { expect(res.body.id).to.be.a('string'); APP_ID = res.body.id; expect(fake1.isDone()).to.be.ok(); - expect(fake2.isDone()).to.be.ok(); taskId = res.body.taskId; }); diff --git a/src/test/appstore-test.js b/src/test/appstore-test.js deleted file mode 100644 index f18c12455..000000000 --- a/src/test/appstore-test.js +++ /dev/null @@ -1,63 +0,0 @@ -/* jslint node:true */ -/* global it:false */ -/* global describe:false */ -/* global before:false */ -/* global after:false */ -/* global beforeEach:false */ - -'use strict'; - -const appstore = require('../appstore.js'), - common = require('./common.js'), - expect = require('expect.js'), - nock = require('nock'); - -const APP_ID = 'appid'; -const APPSTORE_APP_ID = 'appstoreappid'; - -describe('Appstore', function () { - const { setup, cleanup, appstoreToken, mockApiServerOrigin } = common; - - before(setup); - before(() => { if (!nock.isActive()) nock.activate(); }); - after(cleanup); - - beforeEach(nock.cleanAll); - - it('can purchase an app', async function () { - const scope1 = nock(mockApiServerOrigin) - .post(`/api/v1/cloudronapps?accessToken=${appstoreToken}`, function () { return true; }) - .reply(201, {}); - - await appstore.purchaseApp({ appId: APP_ID, appstoreId: APPSTORE_APP_ID, manifestId: APPSTORE_APP_ID }); - expect(scope1.isDone()).to.be.ok(); - }); - - it('unpurchase succeeds if app was never purchased', async function () { - const scope1 = nock(mockApiServerOrigin) - .get(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`) - .reply(404, {}); - - const scope2 = nock(mockApiServerOrigin) - .delete(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`, function () { return true; }) - .reply(204, {}); - - await appstore.unpurchaseApp(APP_ID, { appstoreId: APPSTORE_APP_ID, manifestId: APPSTORE_APP_ID }); - expect(scope1.isDone()).to.be.ok(); - expect(scope2.isDone()).to.not.be.ok(); - }); - - it('can unpurchase an app', async function () { - const scope1 = nock(mockApiServerOrigin) - .get(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`) - .reply(200, {}); - - const scope2 = nock(mockApiServerOrigin) - .delete(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`, function () { return true; }) - .reply(204, {}); - - await appstore.unpurchaseApp(APP_ID, { appstoreId: APPSTORE_APP_ID, manifestId: APPSTORE_APP_ID }); - expect(scope1.isDone()).to.be.ok(); - expect(scope2.isDone()).to.be.ok(); - }); -});