diff --git a/scripts/cloudron-setup b/scripts/cloudron-setup index 87b7d92e9..d116a3824 100755 --- a/scripts/cloudron-setup +++ b/scripts/cloudron-setup @@ -49,7 +49,7 @@ webServerOrigin="https://cloudron.io" sourceTarballUrl="" rebootServer="true" -args=$(getopt -o "" -l "help,skip-baseimage-init,provider:,version:,env:,skip-reboot" -n "$0" -- "$@") +args=$(getopt -o "" -l "help,skip-baseimage-init,provider:,version:,env:,skip-reboot,license:" -n "$0" -- "$@") eval set -- "${args}" while true; do @@ -66,6 +66,7 @@ while true; do webServerOrigin="https://staging.cloudron.io" fi shift 2;; + --license) license="$2"; shift 2;; --skip-baseimage-init) initBaseImage="false"; shift;; --skip-reboot) rebootServer="false"; shift;; --) break;; @@ -205,6 +206,8 @@ cat > "/etc/cloudron/cloudron.conf" < /etc/cloudron/LICENSE + if ! /bin/bash "${box_src_tmp_dir}/scripts/installer.sh" &>> "${LOG_FILE}"; then echo "Failed to install cloudron. See ${LOG_FILE} for details" exit 1 diff --git a/src/appstore.js b/src/appstore.js index cb91af9be..9559baa29 100644 --- a/src/appstore.js +++ b/src/appstore.js @@ -6,6 +6,7 @@ exports = module.exports = { getAppVersion: getAppVersion, registerWithLoginCredentials: registerWithLoginCredentials, + registerWithLicense: registerWithLicense, purchaseApp: purchaseApp, unpurchaseApp: unpurchaseApp, @@ -386,6 +387,17 @@ function registerCloudron(data, callback) { }); } +function registerWithLicense(license, callback) { + assert.strictEqual(typeof license, 'string'); + assert.strictEqual(typeof callback, 'function'); + + getCloudronToken(function (error, token) { + if (token) return callback(new AppstoreError(AppstoreError.ALREADY_REGISTERED)); + + registerCloudron({ license }, callback); + }); +} + function registerWithLoginCredentials(options, callback) { assert.strictEqual(typeof options, 'object'); assert.strictEqual(typeof callback, 'function'); @@ -396,8 +408,8 @@ function registerWithLoginCredentials(options, callback) { registerUser(options.email, options.password, done); } - getCloudronToken(function (error) { - if (!error || error.reason !== AppstoreError.NOT_REGISTERED) return callback(new AppstoreError(AppstoreError.ALREADY_REGISTERED)); + getCloudronToken(function (error, token) { + if (token) return callback(new AppstoreError(AppstoreError.ALREADY_REGISTERED)); maybeSignup(function (error) { if (error) return callback(error); diff --git a/src/provision.js b/src/provision.js index eff2b524c..b773d3b5f 100644 --- a/src/provision.js +++ b/src/provision.js @@ -6,10 +6,14 @@ exports = module.exports = { activate: activate, getStatus: getStatus, + autoRegister: autoRegister, + ProvisionError: ProvisionError }; -var assert = require('assert'), +var appstore = require('./appstore.js'), + AppstoreError = require('./appstore.js').AppstoreError, + assert = require('assert'), async = require('async'), backups = require('./backups.js'), BackupsError = require('./backups.js').BackupsError, @@ -21,7 +25,9 @@ var assert = require('assert'), domains = require('./domains.js'), DomainsError = domains.DomainsError, eventlog = require('./eventlog.js'), + fs = require('fs'), mail = require('./mail.js'), + paths = require('./paths.js'), safe = require('safetydance'), semver = require('semver'), settingsdb = require('./settingsdb.js'), @@ -323,3 +329,22 @@ function getStatus(callback) { }); }); } + +function autoRegister(callback) { + assert.strictEqual(typeof callback, 'function'); + + if (!fs.existsSync(paths.LICENSE_FILE)) return callback(); + + const license = safe.fs.readFileSync(paths.LICENSE_FILE, 'utf8'); + if (!license) return callback(new ProvisionError(ProvisionError.EXTERNAL_ERROR, 'Cannot read license')); + + appstore.registerWithLicense(license, function (error) { + if (error && error.reason !== AppstoreError.ALREADY_REGISTERED) { + debug(error); + debug('Failed to auto-register Cloudron with license. Please contact support@cloudron.io'); + return; // does not call callback on purpose. the server just 'hangs' with the above error + } + + callback(); + }); +} diff --git a/src/routes/test/appstore-test.js b/src/routes/test/appstore-test.js index 22d23f9d4..47f40c9c5 100644 --- a/src/routes/test/appstore-test.js +++ b/src/routes/test/appstore-test.js @@ -87,7 +87,7 @@ describe('Appstore Apps API', function () { .reply(200, { userId: 'userId', accessToken: 'SECRET_TOKEN' }); var scope2 = nock(config.apiServerOrigin()) - .post('/api/v1/register_cloudron?accessToken=SECRET_TOKEN', (body) => !!body.domain) + .post('/api/v1/register_cloudron', (body) => !!body.domain && body.accessToken === 'SECRET_TOKEN') .reply(201, { cloudronId: 'cid', cloudronToken: 'CLOUDRON_TOKEN', licenseKey: 'lkey' }); superagent.post(SERVER_URL + '/api/v1/appstore/register_cloudron') @@ -155,7 +155,7 @@ describe('Subscription API - no signup', function () { .reply(200, { userId: 'userId', accessToken: 'SECRET_TOKEN' }); var scope2 = nock(config.apiServerOrigin()) - .post('/api/v1/register_cloudron?accessToken=SECRET_TOKEN', (body) => !!body.domain) + .post('/api/v1/register_cloudron', (body) => !!body.domain && body.accessToken === 'SECRET_TOKEN') .reply(201, { cloudronId: 'cid', cloudronToken: 'CLOUDRON_TOKEN', licenseKey: 'lkey' }); superagent.post(SERVER_URL + '/api/v1/appstore/register_cloudron') @@ -194,7 +194,7 @@ describe('Subscription API - signup', function () { .reply(200, { userId: 'userId', accessToken: 'SECRET_TOKEN' }); var scope3 = nock(config.apiServerOrigin()) - .post('/api/v1/register_cloudron?accessToken=SECRET_TOKEN', (body) => !!body.domain) + .post('/api/v1/register_cloudron', (body) => !!body.domain && body.accessToken === 'SECRET_TOKEN') .reply(201, { cloudronId: 'cid', cloudronToken: 'CLOUDRON_TOKEN', licenseKey: 'lkey' }); superagent.post(SERVER_URL + '/api/v1/appstore/register_cloudron') diff --git a/src/server.js b/src/server.js index 251c6958e..22fc732c7 100644 --- a/src/server.js +++ b/src/server.js @@ -18,6 +18,7 @@ var accesscontrol = require('./accesscontrol.js'), middleware = require('./middleware'), passport = require('passport'), path = require('path'), + provision = require('./provision.js'), routes = require('./routes/index.js'), ws = require('ws'); @@ -372,6 +373,7 @@ function start(callback) { async.series([ routes.accesscontrol.initialize, // hooks up authentication strategies into passport database.initialize, + provision.autoRegister, cloudron.initialize, gHttpServer.listen.bind(gHttpServer, config.get('port'), '127.0.0.1'), gSysadminHttpServer.listen.bind(gSysadminHttpServer, config.get('sysadminPort'), '127.0.0.1'),