Files
cloudron-box/src/js/client.js

1973 lines
68 KiB
JavaScript
Raw Normal View History

2018-01-22 13:01:38 -08:00
'use strict';
/* global $:false */
/* global angular:false */
/* global EventSource:false */
/* global asyncForEach:false */
2018-01-22 13:01:38 -08:00
angular.module('Application').service('Client', ['$http', '$interval', 'md5', 'Notification', function ($http, $interval, md5, Notification) {
var client = null;
// variable available only here to avoid this._property pattern
var token = null;
// Keep this in sync with docs and constants.js, docker.js
var DEFAULT_MEMORY_LIMIT = 1024 * 1024 * 256;
function ClientError(statusCode, messageOrObject) {
Error.call(this);
this.name = this.constructor.name;
this.statusCode = statusCode;
if (messageOrObject === null || typeof messageOrObject === 'undefined') {
this.message = 'Empty message or object';
} else if (typeof messageOrObject === 'string') {
this.message = messageOrObject;
} else if (messageOrObject.message) {
this.message = messageOrObject.message;
} else {
this.message = JSON.stringify(messageOrObject);
}
}
function defaultErrorHandler(callback) {
return function (data, status) {
// handle request killed by browser (eg. cors issue)
if (data === null && status === -1) {
client.offline = true;
return callback(new ClientError('Request cancelled by browser'));
}
2018-01-22 13:01:38 -08:00
if (status === 401) return client.login();
if (status >= 500) {
if (!client.offline) client.error(data);
client.offline = true;
2018-01-22 13:01:38 -08:00
return callback(new ClientError(status, data));
}
var obj = data;
try {
obj = JSON.parse(data);
} catch (e) {}
2018-01-22 13:01:38 -08:00
callback(new ClientError(status, obj));
};
}
function defaultSuccessHandler(callback) {
return function (data, status) {
client.offline = false;
return callback(null, data, status);
}
}
2018-01-22 13:01:38 -08:00
// XHR wrapper to set the auth header
function get(url, config, callback) {
if (arguments.length !== 3) {
console.error('GET', arguments);
throw('Wrong number of arguments');
}
2018-01-22 13:01:38 -08:00
config = config || {};
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + token;
return $http.get(client.apiOrigin + url, config)
.success(defaultSuccessHandler(callback))
.error(defaultErrorHandler(callback));
2018-01-22 13:01:38 -08:00
}
function head(url, config, callback) {
if (arguments.length !== 3) {
console.error('HEAD', arguments);
throw('Wrong number of arguments');
}
2018-01-22 13:01:38 -08:00
config = config || {};
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + token;
return $http.head(client.apiOrigin + url, config)
.success(defaultSuccessHandler(callback))
.error(defaultErrorHandler(callback));
2018-01-22 13:01:38 -08:00
}
function post(url, data, config, callback) {
if (arguments.length !== 4) {
console.error('POST', arguments);
throw('Wrong number of arguments');
}
2018-01-22 13:01:38 -08:00
data = data || {};
config = config || {};
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + token;
return $http.post(client.apiOrigin + url, data, config)
.success(defaultSuccessHandler(callback))
.error(defaultErrorHandler(callback));
2018-01-22 13:01:38 -08:00
}
function put(url, data, config, callback) {
if (arguments.length !== 4) {
console.error('PUT', arguments);
throw('Wrong number of arguments');
}
2018-01-22 13:01:38 -08:00
data = data || {};
config = config || {};
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + token;
return $http.put(client.apiOrigin + url, data, config)
.success(defaultSuccessHandler(callback))
.error(defaultErrorHandler(callback));
2018-01-22 13:01:38 -08:00
}
function del(url, config, callback) {
if (arguments.length !== 3) {
console.error('DEL', arguments);
throw('Wrong number of arguments');
}
2018-01-22 13:01:38 -08:00
config = config || {};
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + token;
return $http.delete(client.apiOrigin + url, config)
.success(defaultSuccessHandler(callback))
.error(defaultErrorHandler(callback));
2018-01-22 13:01:38 -08:00
}
function Client() {
this.offline = false;
2018-01-22 13:01:38 -08:00
this._ready = false;
this._configListener = [];
this._readyListener = [];
this._userInfo = {
id: null,
username: null,
email: null,
2018-04-26 15:12:29 +02:00
twoFactorAuthenticationEnabled: false
2018-01-22 13:01:38 -08:00
};
this._config = {
apiServerOrigin: null,
webServerOrigin: null,
fqdn: null,
ip: null,
revision: null,
update: { box: null, apps: null },
progress: {},
region: null,
size: null,
2018-08-28 18:55:13 -07:00
memory: 0,
edition: null
2018-01-22 13:01:38 -08:00
};
this._installedApps = [];
this._installedAppsById = {};
2018-01-22 13:01:38 -08:00
this._clientId = '<%= oauth.clientId %>';
this._clientSecret = '<%= oauth.clientSecret %>';
// window.location fallback for websocket connections which do not have relative uris
this.apiOrigin = '<%= oauth.apiOrigin %>' || window.location.origin;
this.avatar = '';
this.resetAvatar();
this.setToken(localStorage.token);
}
Client.prototype.error = function (error) {
var message = '';
if (typeof error === 'object') {
message = error.message || error;
} else {
message = error;
}
Notification.error({ title: 'Cloudron Error', message: message });
};
Client.prototype.clearNotifications = function () {
Notification.clearAll();
};
2018-01-22 13:01:38 -08:00
/*
If `action` is a non-empty string, it will be treated as a url, if it is a function, that function will be exectued on click
2018-01-22 13:01:38 -08:00
*/
Client.prototype.notify = function (title, message, persistent, type, action) {
2018-01-22 13:01:38 -08:00
var options = { title: title, message: message};
if (persistent) options.delay = 'never'; // any non Number means never timeout
2018-01-22 13:01:38 -08:00
if (action) {
options.onClick = function (/* params */) {
// if action is a string, we assume it is a link
if (typeof action === 'string' && action !== '') window.location = action;
else if (typeof action === 'function') action();
else console.warn('Notification action is not supported.', action);
};
2018-01-22 13:01:38 -08:00
}
if (type === 'error') Notification.error(options);
else if (type === 'success') Notification.success(options);
else if (type === 'info') Notification.info(options);
else if (type === 'warning') Notification.warning(options);
else throw('Invalid notification type "' + type + '"');
};
Client.prototype.setReady = function () {
if (this._ready) return;
this._ready = true;
this._readyListener.forEach(function (callback) {
callback();
});
// clear the listeners, we only callback once!
this._readyListener = [];
};
Client.prototype.onReady = function (callback) {
if (this._ready) callback();
else this._readyListener.push(callback);
};
Client.prototype.onConfig = function (callback) {
this._configListener.push(callback);
if (this._config && this._config.apiServerOrigin) callback(this._config);
};
Client.prototype.resetAvatar = function () {
this.avatar = this.apiOrigin + '/api/v1/cloudron/avatar?' + String(Math.random()).slice(2);
var favicon = $('#favicon');
if (favicon) favicon.attr('href', this.avatar);
};
Client.prototype.setUserInfo = function (userInfo) {
// In order to keep the angular bindings alive, set each property individually
this._userInfo.id = userInfo.id;
this._userInfo.username = userInfo.username;
this._userInfo.email = userInfo.email;
this._userInfo.fallbackEmail = userInfo.fallbackEmail;
this._userInfo.displayName = userInfo.displayName;
2018-04-26 15:12:29 +02:00
this._userInfo.twoFactorAuthenticationEnabled = userInfo.twoFactorAuthenticationEnabled;
2018-08-03 09:34:39 -07:00
this._userInfo.admin = userInfo.admin;
2018-01-22 13:01:38 -08:00
this._userInfo.gravatar = 'https://www.gravatar.com/avatar/' + md5.createHash(userInfo.email) + '.jpg?s=24&d=mm';
this._userInfo.gravatarHuge = 'https://www.gravatar.com/avatar/' + md5.createHash(userInfo.email) + '.jpg?s=128&d=mm';
};
Client.prototype.setConfig = function (config) {
var that = this;
2018-08-28 21:35:17 -07:00
// derive feature flags from edition
2018-10-30 22:51:59 -07:00
config.managed = config.edition === 'hostingprovider' || config.provider === 'caas';
2018-10-30 21:07:37 -07:00
2018-08-28 21:35:17 -07:00
config.features = {
2018-10-30 21:07:37 -07:00
spaces: config.edition === 'education'
2018-08-28 21:35:17 -07:00
};
2018-01-22 13:01:38 -08:00
angular.copy(config, this._config);
this._configListener.forEach(function (callback) {
callback(that._config);
});
};
Client.prototype.getInstalledApps = function () {
return this._installedApps;
};
Client.prototype.getUserInfo = function () {
return this._userInfo;
};
Client.prototype.getConfig = function () {
return this._config;
};
Client.prototype.setToken = function (accessToken) {
if (!accessToken) localStorage.removeItem('token');
else localStorage.token = accessToken;
// set the token closure
token = accessToken;
};
Client.prototype.getToken = function () {
return token;
};
Client.prototype.makeURL = function (url) {
if (url.indexOf('?') === -1) {
return this.apiOrigin + url + '?access_token=' + token;
} else {
return this.apiOrigin + url + '&access_token=' + token;
}
};
2018-01-22 13:01:38 -08:00
/*
* Rest API wrappers
*/
Client.prototype.config = function (callback) {
get('/api/v1/config', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data));
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.userInfo = function (callback) {
get('/api/v1/profile', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data));
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.changeCloudronAvatar = function (avatarFile, callback) {
var fd = new FormData();
fd.append('avatar', avatarFile);
var config = {
2018-01-22 13:01:38 -08:00
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
};
post('/api/v1/settings/cloudron_avatar', fd, config, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.changeCloudronName = function (name, callback) {
var data = {
name: name
};
post('/api/v1/settings/cloudron_name', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.installApp = function (id, manifest, title, config, callback) {
var that = this;
var data = {
appStoreId: id + '@' + manifest.version,
location: config.location,
domain: config.domain,
portBindings: config.portBindings,
accessRestriction: config.accessRestriction,
cert: config.cert,
key: config.key,
sso: config.sso
};
post('/api/v1/apps/install', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
// put new app with amended title in cache
data.manifest = { title: title };
var icons = that.getAppIconUrls(data);
data.iconUrl = icons.cloudron;
data.iconUrlStore = icons.store;
data.progress = 0;
callback(null, data.id);
});
2018-01-22 13:01:38 -08:00
};
2018-05-28 00:47:53 -07:00
Client.prototype.cloneApp = function (appId, config, callback) {
var data = {
location: config.location,
domain: config.domain,
portBindings: config.portBindings,
backupId: config.backupId
};
post('/api/v1/apps/' + appId + '/clone', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
2018-05-28 00:47:53 -07:00
2018-06-26 08:33:04 -07:00
callback(null, data);
});
2018-05-28 00:47:53 -07:00
};
2018-01-22 13:01:38 -08:00
Client.prototype.restoreApp = function (appId, backupId, password, callback) {
var data = { password: password, backupId: backupId };
post('/api/v1/apps/' + appId + '/restore', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.backupApp = function (appId, callback) {
var data = {};
post('/api/v1/apps/' + appId + '/backup', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.uninstallApp = function (appId, password, callback) {
var data = { password: password };
post('/api/v1/apps/' + appId + '/uninstall', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
2019-01-15 11:13:04 -08:00
Client.prototype.configureApp = function (id, data, callback) {
post('/api/v1/apps/' + id + '/configure', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.updateApp = function (id, manifest, callback) {
var data = {
appStoreId: manifest.id + '@' + manifest.version
};
post('/api/v1/apps/' + id + '/update', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.startApp = function (id, callback) {
post('/api/v1/apps/' + id + '/start', {}, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.stopApp = function (id, callback) {
post('/api/v1/apps/' + id + '/stop', {}, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.debugApp = function (id, state, callback) {
var data = {
appId: id,
debugMode: state ? {
readonlyRootfs: true,
cmd: [ '/bin/bash', '-c', 'echo "Repair mode. Use the webterminal or cloudron exec to repair. Sleeping" && sleep infinity' ]
} : null
};
post('/api/v1/apps/' + id + '/configure', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.version = function (callback) {
get('/api/v1/cloudron/status', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
}).error(defaultErrorHandler(callback));
};
Client.prototype.getStatus = function (callback) {
get('/api/v1/cloudron/status', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200 || typeof data !== 'object') return callback(new ClientError(status, data));
callback(null, data);
}).error(defaultErrorHandler(callback));
};
Client.prototype.setBackupConfig = function (backupConfig, callback) {
post('/api/v1/settings/backup_config', backupConfig, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getBackupConfig = function (callback) {
get('/api/v1/settings/backup_config', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
2018-08-02 19:44:00 -07:00
2018-10-31 16:03:09 +01:00
Client.prototype.setDynamicDnsConfig = function (enabled, callback) {
post('/api/v1/settings/dynamic_dns', { enabled: enabled }, null, function (error, data, status) {
if (error) return callback(error);
2018-10-31 16:03:09 +01:00
if (status !== 200) return callback(new ClientError(status, data));
callback(null);
});
2018-10-31 16:03:09 +01:00
};
Client.prototype.getDynamicDnsConfig = function (callback) {
get('/api/v1/settings/dynamic_dns', null, function (error, data, status) {
if (error) return callback(error);
2018-10-31 16:03:09 +01:00
if (status !== 200) return callback(new ClientError(status, data));
2018-10-31 16:03:09 +01:00
callback(null, data.enabled);
});
2018-10-31 16:03:09 +01:00
};
Client.prototype.getUpdateInfo = function (callback) {
get('/api/v1/cloudron/update', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.checkForUpdates = function (callback) {
post('/api/v1/cloudron/check_for_updates', {}, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
client.refreshConfig(callback);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.setAppAutoupdatePattern = function (pattern, callback) {
post('/api/v1/settings/app_autoupdate_pattern', { pattern: pattern }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.getAppAutoupdatePattern = function (callback) {
get('/api/v1/settings/app_autoupdate_pattern', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.setBoxAutoupdatePattern = function (pattern, callback) {
post('/api/v1/settings/box_autoupdate_pattern', { pattern: pattern }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.getBoxAutoupdatePattern = function (callback) {
get('/api/v1/settings/box_autoupdate_pattern', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.setAppstoreConfig = function (appstoreConfig, callback) {
post('/api/v1/settings/appstore_config', appstoreConfig, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getAppstoreConfig = function (callback) {
get('/api/v1/settings/appstore_config', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getRemoteSupport = function (callback) {
get('/api/v1/support/remote_support', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data.enabled);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.enableRemoteSupport = function (enable, callback) {
post('/api/v1/support/remote_support', { enable: enable }, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getBackups = function (callback) {
get('/api/v1/backups', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.backups);
});
2018-01-22 13:01:38 -08:00
};
2018-12-08 20:21:11 -08:00
Client.prototype.getLatestTaskByType = function (type, callback) {
get('/api/v1/tasks?page=1&per_page=1&type=' + type, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2019-01-06 14:52:36 -08:00
callback(null, data.tasks.length ? data.tasks[0] : null);
});
2018-12-08 20:21:11 -08:00
};
Client.prototype.getTask = function (taskId, callback) {
get('/api/v1/tasks/' + taskId, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-11-19 17:34:14 -08:00
callback(null, data);
});
2018-11-19 17:34:14 -08:00
};
2018-12-08 21:45:49 -08:00
Client.prototype.getTaskLogs = function (taskId, follow, lines, callback) {
if (follow) {
var eventSource = new EventSource(client.apiOrigin + '/api/v1/tasks/' + taskId + '/logstream?lines=' + lines + '&access_token=' + token);
callback(null, eventSource);
} else {
2019-01-08 13:12:37 -08:00
get('/api/v1/services/' + taskId + '/logs?lines=' + lines, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-12-08 21:45:49 -08:00
callback(null, data);
});
2018-12-08 21:45:49 -08:00
}
};
2018-11-17 19:55:37 -08:00
Client.prototype.startBackup = function (callback) {
post('/api/v1/backups', {}, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
2018-12-08 20:21:11 -08:00
callback(null, data.taskId);
});
2018-11-17 19:55:37 -08:00
};
2018-11-19 17:34:14 -08:00
Client.prototype.stopTask = function (taskId, callback) {
post('/api/v1/tasks/' + taskId + '/stop', {}, null, function (error, data, status) {
if (error) return callback(error);
2019-01-06 14:52:36 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.restore = function (backupConfig, backupId, version, callback) {
var data = {
backupConfig: backupConfig,
backupId: backupId,
version: version
};
post('/api/v1/cloudron/restore', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getNotifications = function (acknowledged, page, perPage, callback) {
var config = {
params: {
page: page,
per_page: perPage
}
};
if (typeof acknowledged === 'boolean') config.params.acknowledged = acknowledged;
get('/api/v1/notifications', config, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data.notifications);
});
};
2019-01-07 18:04:52 +01:00
Client.prototype.ackNotification = function (notificationId, callback) {
post('/api/v1/notifications/' + notificationId, {}, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 204) return callback(new ClientError(status));
callback(null);
});
};
2019-01-23 16:44:57 +01:00
Client.prototype.getEvent = function (eventId, callback) {
get('/api/v1/cloudron/eventlog/' + eventId, {}, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data.event);
});
};
Client.prototype.getEventLogs = function (actions, search, page, perPage, callback) {
2018-01-22 13:01:38 -08:00
var config = {
params: {
actions: actions,
2018-01-22 13:01:38 -08:00
search: search,
page: page,
per_page: perPage
}
};
2018-12-11 19:03:35 +01:00
get('/api/v1/cloudron/eventlog', config, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.eventlogs);
});
2018-01-22 13:01:38 -08:00
};
2018-06-11 20:10:57 +02:00
Client.prototype.getPlatformLogs = function (unit, follow, lines, callback) {
2018-01-22 13:01:38 -08:00
if (follow) {
2018-06-11 20:10:57 +02:00
var eventSource = new EventSource(client.apiOrigin + '/api/v1/cloudron/logstream/' + unit + '?lines=' + lines + '&access_token=' + token);
2018-01-22 13:01:38 -08:00
callback(null, eventSource);
} else {
2019-01-08 13:12:37 -08:00
get('/api/v1/cloudron/logs/' + unit + '?lines=' + lines, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
}
};
2018-12-02 18:07:11 -08:00
Client.prototype.getServiceLogs = function (serviceName, follow, lines, callback) {
2018-11-26 14:49:50 +01:00
if (follow) {
2018-12-02 18:07:11 -08:00
var eventSource = new EventSource(client.apiOrigin + '/api/v1/services/' + serviceName + '/logstream?lines=' + lines + '&access_token=' + token);
2018-11-26 14:49:50 +01:00
callback(null, eventSource);
} else {
2019-01-08 13:12:37 -08:00
get('/api/v1/services/' + serviceName + '/logs?lines=' + lines, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-11-26 14:49:50 +01:00
callback(null, data);
});
2018-11-26 14:49:50 +01:00
}
};
2018-01-22 13:01:38 -08:00
Client.prototype.getApps = function (callback) {
get('/api/v1/apps', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.apps);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getAppLogs = function (appId, follow, lines, callback) {
if (follow) {
var eventSource = new EventSource(client.apiOrigin + '/api/v1/apps/' + appId + '/logstream?lines=' + lines + '&access_token=' + token);
callback(null, eventSource);
} else {
get('/api/v1/apps/' + appId + '/logs', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
}
};
Client.prototype.getAppBackups = function (appId, callback) {
get('/api/v1/apps/' + appId + '/backups', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.backups);
});
2018-01-22 13:01:38 -08:00
};
2018-12-02 18:07:11 -08:00
Client.prototype.getServices = function (callback) {
get('/api/v1/services', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-12-02 18:07:11 -08:00
callback(null, data.services);
});
2018-11-15 19:59:24 +01:00
};
2018-12-02 18:07:11 -08:00
Client.prototype.getService = function (serviceName, callback) {
get('/api/v1/services/' + serviceName, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-12-02 18:07:11 -08:00
callback(null, data.service);
});
2018-11-15 19:59:24 +01:00
};
2018-12-02 18:07:11 -08:00
Client.prototype.configureService = function (serviceName, memoryLimit, callback) {
post('/api/v1/services/' + serviceName, { memory: memoryLimit }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
2018-11-20 16:53:42 +01:00
};
2018-12-02 18:07:11 -08:00
Client.prototype.restartService = function (serviceName, callback) {
post('/api/v1/services/' + serviceName + '/restart', {}, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.getUsers = function (search, page, perPage, callback) {
if (typeof search === 'function') {
callback = search;
search = '';
page = 1;
perPage = 1000;
}
var config = {
params: {
page: page,
per_page: perPage
}
};
if (search) config.params.search = search;
get('/api/v1/users', config, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.users);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getUser = function (userId, callback) {
get('/api/v1/users/' + userId, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.getGroups = function (callback) {
get('/api/v1/groups', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.groups);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.setGroups = function (userId, groupIds, callback) {
put('/api/v1/users/' + userId + '/groups', { groupIds: groupIds }, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getGroup = function (groupId, callback) {
get('/api/v1/groups/' + groupId, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
2018-07-26 11:38:20 -07:00
Client.prototype.createGroup = function (name, callback) {
2018-01-22 13:01:38 -08:00
var data = {
2018-07-26 11:38:20 -07:00
name: name
2018-01-22 13:01:38 -08:00
};
post('/api/v1/groups', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
2018-07-26 11:38:20 -07:00
Client.prototype.updateGroup = function (id, name, callback) {
var data = {
2018-07-26 11:38:20 -07:00
name: name
};
post('/api/v1/groups/' + id, data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
Client.prototype.setGroupMembers = function (id, userIds, callback) {
var data = {
userIds: userIds
};
put('/api/v1/groups/' + id + '/members', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.removeGroup = function (groupId, password, callback) {
var config = {
data: {
password: password
},
headers: {
'Content-Type': 'application/json'
}
};
del('/api/v1/groups/' + groupId, config, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getApp = function (appId, callback) {
get('/api/v1/apps/' + appId, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-06-25 18:55:07 -07:00
callback(null, data);
});
2018-06-25 18:55:07 -07:00
};
Client.prototype.getCachedApp = function (appId, callback) {
2018-01-22 13:01:38 -08:00
var appFound = null;
this._installedApps.some(function (app) {
if (app.id === appId) {
appFound = app;
return true;
} else {
return false;
}
});
if (appFound) return callback(null, appFound);
else return callback(new Error('App not found'));
};
Client.prototype.getCachedAppSync = function (appId) {
var appFound = null;
this._installedApps.some(function (app) {
if (app.id === appId) {
appFound = app;
return true;
} else {
return false;
}
});
return appFound;
};
2018-01-22 13:01:38 -08:00
Client.prototype.getAppIconUrls = function (app) {
return {
cloudron: app.iconUrl ? (this.apiOrigin + app.iconUrl + '?access_token=' + token) : null,
store: app.appStoreId ? (this._config.apiServerOrigin + '/api/v1/apps/' + app.appStoreId + '/versions/' + app.manifest.version + '/icon') : null
};
};
Client.prototype.createInvite = function (userId, callback) {
post('/api/v1/users/' + userId + '/create_invite', {}, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.resetToken);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.sendInvite = function (userId, callback) {
post('/api/v1/users/' + userId + '/send_invite', {}, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null);
});
};
2018-10-30 13:42:57 -07:00
Client.prototype.setup = function (domain, zoneName, provider, config, tlsConfig, callback) {
2018-01-22 13:01:38 -08:00
var data = {
2018-10-30 13:42:57 -07:00
dnsConfig: {
domain: domain,
zoneName: zoneName,
provider: provider,
config: config,
tlsConfig: tlsConfig
}
2018-01-22 13:01:38 -08:00
};
post('/api/v1/cloudron/setup', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.createAdmin = function (username, password, email, displayName, setupToken, callback) {
var that = this;
var data = {
username: username,
password: password,
email: email,
displayName: displayName
};
var query = '';
if (setupToken) query = '?setupToken=' + setupToken;
post('/api/v1/cloudron/activate' + query, data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
that.setToken(data.token);
2018-08-03 10:09:04 -07:00
that.setUserInfo({ username: username, email: email, admin: true, twoFactorAuthenticationEnabled: false });
2018-01-22 13:01:38 -08:00
callback(null, data.activated);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getOAuthClients = function (callback) {
get('/api/v1/clients', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.clients);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.createOAuthClient = function (appId, scope, redirectURI, callback) {
var data = {
appId: appId,
scope: scope,
redirectURI: redirectURI
};
post('/api/v1/clients', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.clients);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.delOAuthClient = function (id, callback) {
del('/api/v1/clients/' + id, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
2018-08-27 16:04:16 -07:00
Client.prototype.createTokenByClientId = function (id, scope, expiresAt, name, callback) {
var data = {
scope: scope,
2018-08-27 16:04:16 -07:00
expiresAt: expiresAt,
name: name || ''
};
post('/api/v1/clients/' + id + '/tokens', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 201) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.token);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getTokensByClientId = function (id, callback) {
get('/api/v1/clients/' + id + '/tokens', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.tokens);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.delTokensByClientId = function (id, callback) {
del('/api/v1/clients/' + id + '/tokens', null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.delToken = function (clientId, tokenId, callback) {
del('/api/v1/clients/' + clientId + '/tokens/' + tokenId, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.update = function (callback) {
var data = { };
post('/api/v1/cloudron/update', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
2018-12-08 20:21:11 -08:00
callback(null, data.taskId);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.isRebootRequired = function (callback) {
get('/api/v1/cloudron/reboot', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null, data.rebootRequired);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.reboot = function (callback) {
post('/api/v1/cloudron/reboot', {}, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.setAdmin = function (domain, password, callback) {
post('/api/v1/domains/' + domain + '/set_admin', { password: password }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.setCertificate = function (certificateFile, keyFile, callback) {
var data = {
cert: certificateFile,
key: keyFile
};
post('/api/v1/settings/certificate', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.disks = function (callback) {
get('/api/v1/cloudron/disks', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.graphs = function (targets, from, callback) {
var config = {
params: {
target: targets,
format: 'json',
from: from
}
};
get('/api/v1/cloudron/graphs', config, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.feedback = function (type, subject, description, appId /* optional */, callback) {
2018-01-22 13:01:38 -08:00
var data = {
type: type,
subject: subject,
description: description,
appId: appId || undefined
2018-01-22 13:01:38 -08:00
};
2018-12-19 10:58:50 -08:00
post('/api/v1/support/feedback', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 201) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
2018-07-26 15:52:06 -07:00
Client.prototype.createUser = function (user, callback) {
2018-01-22 13:01:38 -08:00
var data = {
2018-07-26 15:52:06 -07:00
email: user.email,
displayName: user.displayName,
2018-07-26 15:45:52 -07:00
admin: user.admin
2018-01-22 13:01:38 -08:00
};
2018-07-26 15:52:06 -07:00
if (user.username !== null) data.username = user.username;
2018-01-22 13:01:38 -08:00
post('/api/v1/users', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.updateUser = function (user, callback) {
var data = {
email: user.email,
displayName: user.displayName,
2018-07-26 15:45:52 -07:00
fallbackEmail: user.fallbackEmail,
admin: user.admin
2018-01-22 13:01:38 -08:00
};
post('/api/v1/users/' + user.id, data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.transferOwnership = function (oldOwnerId, newOwnerId, callback) {
var data = {
ownerId: newOwnerId
};
post('/api/v1/users/' + oldOwnerId + '/transfer', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
callback(null);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.removeUser = function (userId, password, callback) {
var config = {
data: {
password: password
},
headers: {
'Content-Type': 'application/json'
}
};
del('/api/v1/users/' + userId, config, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.updateProfile = function (data, callback) {
post('/api/v1/profile', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.changePassword = function (currentPassword, newPassword, callback) {
var data = {
password: currentPassword,
newPassword: newPassword
};
post('/api/v1/profile/password', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
2018-04-26 15:12:29 +02:00
Client.prototype.setTwoFactorAuthenticationSecret = function (callback) {
var data = {};
post('/api/v1/profile/twofactorauthentication', data, null, function (error, data, status) {
if (error) return callback(error);
2018-04-26 15:12:29 +02:00
if (status !== 201) return callback(new ClientError(status, data));
2018-04-26 15:12:29 +02:00
callback(null, data);
});
2018-04-26 15:12:29 +02:00
};
Client.prototype.enableTwoFactorAuthentication = function (totpToken, callback) {
var data = {
totpToken: totpToken
};
post('/api/v1/profile/twofactorauthentication/enable', data, null, function (error, data, status) {
if (error) return callback(error);
2018-04-26 15:12:29 +02:00
if (status !== 202) return callback(new ClientError(status, data));
2018-04-26 15:12:29 +02:00
callback(null);
});
2018-04-26 15:12:29 +02:00
};
Client.prototype.disableTwoFactorAuthentication = function (password, callback) {
var data = {
password: password
};
post('/api/v1/profile/twofactorauthentication/disable', data, null, function (error, data, status) {
if (error) return callback(error);
2018-04-26 15:12:29 +02:00
if (status !== 202) return callback(new ClientError(status, data));
2018-04-26 15:12:29 +02:00
callback(null);
});
2018-04-26 15:12:29 +02:00
};
2018-01-22 13:01:38 -08:00
Client.prototype.refreshUserInfo = function (callback) {
var that = this;
callback = typeof callback === 'function' ? callback : function () {};
this.userInfo(function (error, result) {
if (error) return callback(error);
that.setUserInfo(result);
callback(null);
});
};
Client.prototype.refreshConfig = function (callback) {
var that = this;
callback = typeof callback === 'function' ? callback : function () {};
this.config(function (error, result) {
if (error) return callback(error);
that.getUpdateInfo(function (error, info) { // note: non-admin users may get access denied for this
if (!error) result.update = info.update; // attach update information to config object
2018-01-22 13:01:38 -08:00
that.setConfig(result);
callback(null);
});
2018-01-22 13:01:38 -08:00
});
};
2018-06-26 08:34:05 -07:00
Client.prototype._appPostProcess = function (app) {
2018-01-22 13:01:38 -08:00
// calculate the icon paths
var icons = this.getAppIconUrls(app);
app.iconUrl = icons.cloudron;
app.iconUrlStore = icons.store;
// FIXME have a real message structure, not some string to randomly parse
// extract progress percentage
var installationProgress = app.installationProgress || '';
var progress = parseInt(installationProgress.split(',')[0], 10);
// Unfortunatelly some errors are not actual progress messages, but still have a number in fron like a http status code
if (isNaN(progress) || progress > 100) {
app.progress = 0;
app.message = installationProgress;
} else {
app.progress = progress;
app.message = installationProgress.replace(/.*, /,'');
}
// amend the post install confirm state
app.pendingPostInstallConfirmation = !!localStorage['confirmPostInstall_' + app.id];
2018-01-22 13:01:38 -08:00
return app;
};
2018-06-26 17:12:55 -07:00
function binarySearch(array, pred) {
var lo = -1, hi = array.length;
while (1 + lo !== hi) {
var mi = lo + ((hi - lo) >> 1);
if (pred(array[mi])) {
hi = mi;
} else {
lo = mi;
}
}
return hi;
}
2018-06-26 08:41:25 -07:00
Client.prototype._updateAppCache = function (app) {
var found = -1;
2018-06-26 17:12:55 -07:00
// find by id and not by loc because the app's fqdn might have changed between invokations
2018-06-26 08:41:25 -07:00
for (var i = 0; i < this._installedApps.length; ++i) {
if (this._installedApps[i].id === app.id) {
found = i;
break;
}
}
var tmp = {};
angular.copy(app, tmp);
this._appPostProcess(tmp);
// only replace if the app is already known
2018-06-26 17:12:55 -07:00
if (found !== -1 && this._installedApps[found].fqdn === tmp.fqdn) { // app location has not changed
2018-06-26 08:41:25 -07:00
angular.copy(tmp, this._installedApps[found]);
} else {
2018-06-26 17:12:55 -07:00
if (found !== -1) this._installedApps.splice(found, 1); // remove it
var loc = binarySearch(this._installedApps, function (item) { return item.fqdn.localeCompare(app.fqdn) <= 0; });
this._installedApps.splice(loc, 0, tmp); // insert into sorted fqdn array
2018-06-26 08:41:25 -07:00
}
this._installedAppsById[app.id] = this._installedApps[found];
2018-06-26 08:41:25 -07:00
};
// this requires app:manage permissions
Client.prototype.refreshAppCache = function (id, callback) {
var that = this;
callback = typeof callback === 'function' ? callback : function () {};
this.getApp(id, function (error, app) {
if (error) return callback(error);
that._updateAppCache(app);
callback(null, app);
});
};
2018-01-22 13:01:38 -08:00
Client.prototype.refreshInstalledApps = function (callback) {
var that = this;
callback = typeof callback === 'function' ? callback : function () {};
this.getApps(function (error, apps) {
2018-01-22 13:01:38 -08:00
if (error) return callback(error);
asyncForEach(apps, function (app, iteratorCallback) {
2018-08-03 23:00:25 -07:00
var canManageApp = that._userInfo.admin || that._userInfo.id === app.ownerId;
2018-01-22 13:01:38 -08:00
if (!canManageApp) {
that._updateAppCache(app);
return iteratorCallback();
2018-01-22 13:01:38 -08:00
}
if (that._installedAppsById[app.id] && that._installedAppsById[app.id].ts === app.ts) return iteratorCallback(); // app has not changed
that.refreshAppCache(app.id, iteratorCallback);
}, function iteratorDone(error) {
if (error) return callback(error);
// filter out old apps, going backwards to allow splicing
for (var i = that._installedApps.length - 1; i >= 0; --i) {
if (!apps.some(function (elem) { return (elem.id === that._installedApps[i].id); })) {
var removed = that._installedApps.splice(i, 1);
delete that._installedAppsById[removed[0].id];
}
}
callback(null);
});
2018-01-22 13:01:38 -08:00
});
};
Client.prototype.login = function () {
this.setToken(null);
this._userInfo = {};
var callbackURL = window.location.protocol + '//' + window.location.host + '/login_callback.html';
var scope = 'root,profile,apps';
// generate a state id to protect agains csrf
var state = Math.floor((1 + Math.random()) * 0x1000000000000).toString(16).substring(1);
window.localStorage.oauth2State = state;
// stash for further use in login_callback
window.localStorage.returnTo = '/' + window.location.hash;
window.location.href = this.apiOrigin + '/api/v1/oauth/dialog/authorize?response_type=token&client_id=' + this._clientId + '&redirect_uri=' + callbackURL + '&scope=' + scope + '&state=' + state;
};
Client.prototype.logout = function () {
this.setToken(null);
this._userInfo = {};
// logout from OAuth session
var origin = window.location.protocol + '//' + window.location.host;
window.location.href = this.apiOrigin + '/api/v1/session/logout?redirect=' + origin;
};
2018-06-15 17:16:50 -07:00
// this is ununsed because webadmin uses implicit grant flow
2018-01-22 13:01:38 -08:00
Client.prototype.exchangeCodeForToken = function (code, callback) {
var data = {
grant_type: 'authorization_code',
code: code,
redirect_uri: window.location.protocol + '//' + window.location.host,
client_id: this._clientId,
client_secret: this._clientSecret
};
post('/api/v1/oauth/token?response_type=token&client_id=' + this._clientId, data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.access_token);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.enoughResourcesAvailable = function (app) {
var needed = app.manifest.memoryLimit || DEFAULT_MEMORY_LIMIT; // RAM+Swap
var used = this.getInstalledApps().reduce(function (prev, cur) { return prev + (cur.memoryLimit || cur.manifest.memoryLimit || DEFAULT_MEMORY_LIMIT); }, 0);
var roundedMemory = Math.round(this.getConfig().memory / (1024 * 1024 * 1024)) * 1024 * 1024 * 1024; // round to nearest GB
var totalMemory = roundedMemory * 1.5; // cloudron-system-setup.sh creates equal amount of swap. 1.5 factor is arbitrary
2018-01-22 13:01:38 -08:00
var available = (totalMemory || 0) - used;
return (available - needed) >= 0;
};
Client.prototype.uploadFile = function (appId, file, progressCallback, callback) {
var fd = new FormData();
fd.append('file', file);
var config = {
2018-01-22 13:01:38 -08:00
headers: { 'Content-Type': undefined },
transformRequest: angular.identity,
uploadEventHandlers: {
progress: progressCallback
}
};
post('/api/v1/apps/' + appId + '/upload?file=/tmp/' + file.name, fd, config, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.checkDownloadableFile = function (appId, filePath, callback) {
var config = {
2018-01-22 13:01:38 -08:00
headers: { 'Content-Type': undefined }
};
head('/api/v1/apps/' + appId + '/download?file=' + filePath, config, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
2018-01-23 16:10:09 -08:00
Client.prototype.sendTestMail = function (domain, to, callback) {
2018-01-22 13:01:38 -08:00
var data = {
2018-01-23 16:10:09 -08:00
to: to
2018-01-22 13:01:38 -08:00
};
post('/api/v1/mail/' + domain + '/send_test_mail', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
2018-01-22 13:01:38 -08:00
};
// Domains
Client.prototype.getDomains = function (callback) {
get('/api/v1/domains', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data.domains);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.getDomain = function (domain, callback) {
get('/api/v1/domains/' + domain, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null, data);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.addMailDomain = function (domain, callback) {
post('/api/v1/mail', { domain: domain }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.addDomain = function (domain, zoneName, provider, config, fallbackCertificate, tlsConfig, callback) {
2018-01-22 13:01:38 -08:00
var data = {
domain: domain,
provider: provider,
config: config,
tlsConfig: tlsConfig
2018-01-22 13:01:38 -08:00
};
if (zoneName) data.zoneName = zoneName;
var that = this;
2018-01-22 13:01:38 -08:00
if (fallbackCertificate) data.fallbackCertificate = fallbackCertificate;
// hack until we fix the domains.js
post('/api/v1/domains', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 201) return callback(new ClientError(status, data));
that.addMailDomain(domain, callback);
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.updateDomain = function (domain, zoneName, provider, config, fallbackCertificate, tlsConfig, callback) {
2018-01-22 13:01:38 -08:00
var data = {
provider: provider,
config: config,
tlsConfig: tlsConfig
2018-01-22 13:01:38 -08:00
};
if (zoneName) data.zoneName = zoneName;
var that = this;
2018-01-22 13:01:38 -08:00
if (fallbackCertificate) data.fallbackCertificate = fallbackCertificate;
put('/api/v1/domains/' + domain, data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-07-25 10:51:58 -07:00
that.setDnsRecords(domain, callback); // this is done so that an out-of-sync dkim key can be synced
});
2018-01-22 13:01:38 -08:00
};
Client.prototype.removeMailDomain = function (domain, password, callback) {
2018-01-22 13:01:38 -08:00
var config = {
data: {
password: password
},
headers: {
'Content-Type': 'application/json'
}
};
// FIXME
del('/api/v1/mail/' + domain, config, function (error, data, status) {
if (error) return callback(error);
2018-01-22 13:01:38 -08:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-22 13:01:38 -08:00
callback(null);
});
};
2018-10-24 15:24:23 -07:00
Client.prototype.renewCerts = function (domain, callback) {
post('/api/v1/cloudron/renew_certs', { domain: domain || null }, null, function (error, data, status) {
if (error) return callback(error);
2018-10-24 15:24:23 -07:00
if (status !== 202) return callback(new ClientError(status, data));
2018-12-11 10:17:27 -08:00
callback(null, data.taskId);
});
2018-10-24 15:24:23 -07:00
};
Client.prototype.removeDomain = function (domain, password, callback) {
var config = {
data: {
password: password
},
headers: {
'Content-Type': 'application/json'
}
};
this.removeMailDomain(domain, password, function () {
// hack: ignore errors until we fix the domains.js
del('/api/v1/domains/' + domain, config, function (error, data, status) {
if (error) return callback(error);
if (status !== 204) return callback(new ClientError(status, data));
callback(null);
});
});
2018-01-22 13:01:38 -08:00
};
2018-12-18 15:05:11 -08:00
Client.prototype.prepareDashboardDomain = function (domain, callback) {
var data = {
domain: domain
};
post('/api/v1/cloudron/prepare_dashboard_domain', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null, data.taskId);
});
};
Client.prototype.setDashboardDomain = function (domain, callback) {
var data = {
domain: domain
};
post('/api/v1/cloudron/set_dashboard_domain', data, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 204) return callback(new ClientError(status, data));
callback(null);
});
};
2018-01-23 12:29:57 +01:00
// Email
Client.prototype.getMailConfigForDomain = function (domain, callback) {
get('/api/v1/mail/' + domain, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-23 12:29:57 +01:00
callback(null, data);
});
2018-01-23 12:29:57 +01:00
};
Client.prototype.enableMailForDomain = function (domain, enabled, callback) {
post('/api/v1/mail/' + domain + '/enable', { enabled: enabled }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
2018-01-23 12:29:57 +01:00
};
2018-07-25 10:51:58 -07:00
Client.prototype.setDnsRecords = function (domain, callback) {
post('/api/v1/mail/' + domain + '/dns', {}, null, function (error, data, status) {
if (error) return callback(error);
2018-07-25 10:51:58 -07:00
if (status !== 201) return callback(new ClientError(status, data));
2018-07-25 10:51:58 -07:00
callback(null);
});
2018-07-25 10:51:58 -07:00
};
2018-01-23 12:29:57 +01:00
Client.prototype.getMailStatusForDomain = function (domain, callback) {
get('/api/v1/mail/' + domain + '/status', null, function (error, data, status) {
if (error) return callback(error);
if (status !== 200) return callback(new ClientError(status, data));
2018-01-23 12:29:57 +01:00
callback(null, data);
});
2018-01-23 12:29:57 +01:00
};
Client.prototype.setMailRelay = function (domain, data, callback) {
post('/api/v1/mail/' + domain + '/relay', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-23 12:29:57 +01:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-23 12:29:57 +01:00
callback(null);
});
2018-01-23 12:29:57 +01:00
};
Client.prototype.setCatchallAddresses = function (domain, addresses, callback) {
post('/api/v1/mail/' + domain + '/catch_all', { addresses: addresses }, null, function (error, data, status) {
if (error) return callback(error);
if (status !== 202) return callback(new ClientError(status, data));
callback(null);
});
};
Client.prototype.setMailFromValidation = function (domain, enabled, callback) {
post('/api/v1/mail/' + domain + '/mail_from_validation', { enabled: enabled }, null, function (error, data, status) {
if (error) return callback(error);
2018-01-23 12:29:57 +01:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-23 12:29:57 +01:00
callback(null);
});
2018-01-23 12:29:57 +01:00
};
2018-01-24 16:20:21 +01:00
// Mailboxes
Client.prototype.getMailboxes = function (domain, callback) {
get('/api/v1/mail/' + domain + '/mailboxes', null, function (error, data, status) {
if (error) return callback(error);
2018-01-24 16:20:21 +01:00
if (status !== 200) return callback(new ClientError(status, data));
2018-04-09 15:45:54 +02:00
callback(null, data.mailboxes);
});
2018-01-24 16:20:21 +01:00
};
2018-04-05 14:02:56 +02:00
Client.prototype.getMailbox = function (domain, name, callback) {
get('/api/v1/mail/' + domain + '/mailboxes/' + name, null, function (error, data, status) {
if (error) return callback(error);
2018-01-24 16:20:21 +01:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-24 16:20:21 +01:00
callback(null, data.mailbox);
});
2018-01-24 16:20:21 +01:00
};
2018-04-05 14:02:56 +02:00
Client.prototype.addMailbox = function (domain, name, userId, callback) {
var data = {
name: name,
userId: userId
};
post('/api/v1/mail/' + domain + '/mailboxes', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-24 16:20:21 +01:00
if (status !== 201) return callback(new ClientError(status, data));
2018-01-24 16:20:21 +01:00
callback(null);
});
2018-01-24 16:20:21 +01:00
};
2018-04-05 14:02:56 +02:00
Client.prototype.updateMailbox = function (domain, name, userId, callback) {
var data = {
userId: userId
};
post('/api/v1/mail/' + domain + '/mailboxes/' + name, data, null, function (error, data, status) {
if (error) return callback(error);
2018-04-05 14:02:56 +02:00
if (status !== 204) return callback(new ClientError(status, data));
2018-04-05 14:02:56 +02:00
callback(null);
});
2018-04-05 14:02:56 +02:00
};
Client.prototype.removeMailbox = function (domain, name, callback) {
del('/api/v1/mail/' + domain + '/mailboxes/' + name, null, function (error, data, status) {
if (error) return callback(error);
2018-01-24 16:20:21 +01:00
if (status !== 201) return callback(new ClientError(status, data));
2018-01-24 16:20:21 +01:00
callback(null);
});
2018-01-24 16:20:21 +01:00
};
2018-04-01 19:12:06 +02:00
Client.prototype.listAliases = function (domain, callback) {
get('/api/v1/mail/' + domain + '/aliases', null, function (error, data, status) {
if (error) return callback(error);
2018-04-01 19:12:06 +02:00
if (status !== 200) return callback(new ClientError(status, data));
2018-04-01 19:12:06 +02:00
callback(null, data.aliases);
});
2018-04-01 19:12:06 +02:00
};
2018-04-05 14:02:56 +02:00
Client.prototype.getAliases = function (domain, name, callback) {
get('/api/v1/mail/' + domain + '/aliases/' + name, null, function (error, data, status) {
if (error) return callback(error);
2018-01-25 18:16:47 +01:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-25 18:16:47 +01:00
callback(null, data.aliases);
});
2018-01-25 18:16:47 +01:00
};
2018-04-05 14:02:56 +02:00
Client.prototype.setAliases = function (domain, name, aliases, callback) {
2018-01-25 18:16:47 +01:00
var data = {
aliases: aliases
};
put('/api/v1/mail/' + domain + '/aliases/' + name, data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-26 15:39:02 +01:00
if (status !== 202) return callback(new ClientError(status, data));
2018-01-25 18:16:47 +01:00
callback(null);
});
2018-01-25 18:16:47 +01:00
};
2018-04-01 21:58:12 +02:00
Client.prototype.listMailingLists = function (domain, callback) {
get('/api/v1/mail/' + domain + '/lists', null, function (error, data, status) {
if (error) return callback(error);
2018-04-01 21:58:12 +02:00
if (status !== 200) return callback(new ClientError(status, data));
2018-04-01 21:58:12 +02:00
callback(null, data.lists);
});
2018-04-01 21:58:12 +02:00
};
2018-04-05 14:02:56 +02:00
Client.prototype.getMailingList = function (domain, name, callback) {
get('/api/v1/mail/' + domain + '/lists/' + name, null, function (error, data, status) {
if (error) return callback(error);
2018-01-26 11:31:19 +01:00
if (status !== 200) return callback(new ClientError(status, data));
2018-01-26 11:31:19 +01:00
callback(null, data.list);
});
2018-01-26 11:31:19 +01:00
};
2018-04-06 16:43:43 +02:00
Client.prototype.addMailingList = function (domain, name, members, callback) {
2018-01-26 11:31:19 +01:00
var data = {
2018-04-05 14:02:56 +02:00
name: name,
2018-04-06 16:43:43 +02:00
members: members
2018-01-26 11:31:19 +01:00
};
post('/api/v1/mail/' + domain + '/lists', data, null, function (error, data, status) {
if (error) return callback(error);
2018-01-26 11:31:19 +01:00
if (status !== 201) return callback(new ClientError(status, data));
2018-01-26 11:31:19 +01:00
callback(null);
});
2018-01-26 11:31:19 +01:00
};
2018-04-06 16:43:43 +02:00
Client.prototype.updateMailingList = function (domain, name, members, callback) {
2018-04-05 14:02:56 +02:00
var data = {
2018-04-06 16:43:43 +02:00
members: members
2018-04-05 14:02:56 +02:00
};
post('/api/v1/mail/' + domain + '/lists/' + name, data, null, function (error, data, status) {
if (error) return callback(error);
2018-04-05 14:02:56 +02:00
if (status !== 204) return callback(new ClientError(status, data));
2018-04-05 14:02:56 +02:00
callback(null);
});
2018-04-05 14:02:56 +02:00
};
Client.prototype.removeMailingList = function (domain, name, callback) {
del('/api/v1/mail/' + domain + '/lists/' + name, null, function (error, data, status) {
if (error) return callback(error);
2018-01-30 13:38:06 +01:00
if (status !== 204) return callback(new ClientError(status, data));
2018-01-26 11:31:19 +01:00
callback(null);
});
2018-01-26 11:31:19 +01:00
};
2018-01-22 13:01:38 -08:00
client = new Client();
return client;
}]);