Compare commits

...

14 Commits

Author SHA1 Message Date
Girish Ramakrishnan
3c5987cdad more 7.3.5 changes 2023-01-25 10:22:37 +01:00
Girish Ramakrishnan
e0673d78b9 dns: resolve cname records using unbound
cname record can be external and the original NS may not respond to
recursive queries

(cherry picked from commit e4d9dbb558)
2023-01-25 09:58:24 +01:00
Girish Ramakrishnan
08136a5347 More 7.3.4 changes 2023-01-17 11:18:31 +01:00
Girish Ramakrishnan
98b5c77177 s3: add listing check
This is needed for situations like in cloudflare where the endpoint can
be mistakenly configured with the bucket name like https://xx.r2.cloudflarestorage.com/cloudron-backups .
The upload and del calls work but list and copy does not.

(cherry picked from commit 093fc98ae5)
2023-01-17 11:18:05 +01:00
Girish Ramakrishnan
ea441d0b4b s3: throw any copy errors
(cherry picked from commit 40bcfdba76)
2023-01-17 11:18:00 +01:00
Girish Ramakrishnan
d8b5b49ffd Update manifest format for runtimeDirs change 2023-01-16 12:27:58 +01:00
Girish Ramakrishnan
13fd595e8b contabo: network can be real slow
(cherry picked from commit 68f4f1ba85)
2022-12-24 16:34:18 +01:00
Girish Ramakrishnan
5f11e430bd unbound: disable controller interface explicitly
https://github.com/NLnetLabs/unbound/issues/806
(cherry picked from commit ae30fe25d7)
2022-12-24 16:34:09 +01:00
Girish Ramakrishnan
cfa9f901c1 Fix crash in RBL check
(cherry picked from commit d5793bc7c0)
2022-12-09 00:00:46 +01:00
Girish Ramakrishnan
ce2c9d9ac5 reverseproxy: fix typo in regexp matching
(cherry picked from commit d7d43c73fe)
2022-12-08 10:06:48 +01:00
Girish Ramakrishnan
8d5039da35 7.3.5 changes
(cherry picked from commit a198d1ea8d)
2022-12-08 10:06:43 +01:00
Girish Ramakrishnan
c264ff32c2 du: fix crash when filesystem is cifs/nfs/sshfs
(cherry picked from commit 67cde5a62c)
2022-12-08 08:54:41 +01:00
Johannes Zellner
5e30bea155 Start with a default to not fail if no swap is present
(cherry picked from commit d126f056fc)
2022-12-08 08:54:33 +01:00
Johannes Zellner
2c63a89199 Disallow jupyter hub on demo
(cherry picked from commit db5e0b8fdf)
2022-12-08 08:54:27 +01:00
12 changed files with 57 additions and 20 deletions

10
CHANGES
View File

@@ -2573,4 +2573,14 @@
[7.3.4]
* Display platform update status in the UI
* Fix image pruning
* cloudflare: fix issue where incorrect URL configuration is accepted
[7.3.5]
* du: fix crash when filesystem is cifs/nfs/sshfs
* Start with a default to not fail if no swap is present
* Fix bug in cert cleanup logic causing it to repeatedly cleanup
* Fix crash in RBL check
* unbound: disable controller interface explicitly
* Fix issue where cert renewal logs where not displayed
* Fix loading of mailboxes

View File

@@ -17,7 +17,7 @@
"aws-sdk": "^2.1248.0",
"basic-auth": "^2.0.1",
"body-parser": "^1.20.1",
"cloudron-manifestformat": "^5.19.0",
"cloudron-manifestformat": "^5.19.1",
"connect": "^3.7.0",
"connect-lastmile": "^2.1.1",
"connect-timeout": "^1.9.0",

View File

@@ -236,8 +236,8 @@ while true; do
sleep 10
done
ip4=$(curl -s --fail --connect-timeout 2 --max-time 2 https://ipv4.api.cloudron.io/api/v1/helper/public_ip | sed -n -e 's/.*"ip": "\(.*\)"/\1/p' || true)
ip6=$(curl -s --fail --connect-timeout 2 --max-time 2 https://ipv6.api.cloudron.io/api/v1/helper/public_ip | sed -n -e 's/.*"ip": "\(.*\)"/\1/p' || true)
ip4=$(curl -s --fail --connect-timeout 10 --max-time 10 https://ipv4.api.cloudron.io/api/v1/helper/public_ip | sed -n -e 's/.*"ip": "\(.*\)"/\1/p' || true)
ip6=$(curl -s --fail --connect-timeout 10 --max-time 10 https://ipv6.api.cloudron.io/api/v1/helper/public_ip | sed -n -e 's/.*"ip": "\(.*\)"/\1/p' || true)
url4=""
url6=""

View File

@@ -179,8 +179,8 @@ systemctl disable systemd-resolved || true
# on vultr, ufw is enabled by default. we have our own firewall
ufw disable || true
# we need unbound to work as this is required for installer.sh to do any DNS requests
echo -e "server:\n\tinterface: 127.0.0.1\n" > /etc/unbound/unbound.conf.d/cloudron-network.conf
# we need unbound to work as this is required for installer.sh to do any DNS requests. control-enable is for https://github.com/NLnetLabs/unbound/issues/806
echo -e "server:\n\tinterface: 127.0.0.1\n\nremote-control:\n\tcontrol-enable: no\n" > /etc/unbound/unbound.conf.d/cloudron-network.conf
systemctl restart unbound
# Ubuntu 22 has private home directories by default (https://discourse.ubuntu.com/t/private-home-directories-for-ubuntu-21-04-onwards/)

View File

@@ -14,3 +14,8 @@ server:
# enable below for logging to journalctl -u unbound
# verbosity: 5
# log-queries: yes
# https://github.com/NLnetLabs/unbound/issues/806
remote-control:
control-enable: no

View File

@@ -229,7 +229,11 @@ async function copy(backupConfig, srcRemotePath, destRemotePath, progressCallbac
const newFilePath = backupFormat.api(format).getBackupFilePath(backupConfig, destRemotePath);
const startTime = new Date();
await safe(storage.api(provider).copy(backupConfig, oldFilePath, newFilePath, progressCallback));
const [copyError] = await safe(storage.api(provider).copy(backupConfig, oldFilePath, newFilePath, progressCallback));
if (copyError) {
debug(`copy: copied to ${destRemotePath} errored. error: ${copyError.message}`);
throw copyError;
}
debug(`copy: copied successfully to ${destRemotePath}. Took ${(new Date() - startTime)/1000} seconds`);
}

View File

@@ -40,6 +40,7 @@ exports = module.exports = {
DEMO_USERNAME: 'cloudron',
DEMO_BLACKLISTED_APPS: [
'org.jupyter.cloudronapp',
'com.github.cloudtorrent',
'net.alltubedownload.cloudronapp',
'com.adguard.home.cloudronapp',

View File

@@ -7,7 +7,8 @@ const assert = require('assert'),
debug = require('debug')('box:dns/waitfordns'),
dig = require('../dig.js'),
promiseRetry = require('../promise-retry.js'),
safe = require('safetydance');
safe = require('safetydance'),
_ = require('underscore');
async function resolveIp(hostname, type, options) {
assert.strictEqual(typeof hostname, 'string');
@@ -20,12 +21,12 @@ async function resolveIp(hostname, type, options) {
if (!error && results.length !== 0) return results;
// try CNAME record at authoritative server
debug(`resolveIp: Checking if ${hostname} has CNAME record at ${options.server}`);
debug(`resolveIp: No A record. Checking if ${hostname} has CNAME record at ${options.server}`);
const cnameResults = await dig.resolve(hostname, 'CNAME', options);
if (cnameResults.length === 0) return cnameResults;
// recurse lookup the CNAME record
debug(`resolveIp: Resolving ${hostname}'s CNAME record ${cnameResults[0]}`);
debug(`resolveIp: CNAME record found. Resolving ${hostname}'s CNAME record ${cnameResults[0]} using unbound`);
return await dig.resolve(cnameResults[0], type, options);
}

View File

@@ -539,7 +539,7 @@ async function checkRblStatus(domain) {
const [error2, txtRecords] = await safe(dig.resolve(flippedIp + '.' + rblServer.dns, 'TXT', DNS_OPTIONS));
result.txtRecords = error2 || !txtRecords ? 'No txt record' : txtRecords.map(x => x.join(''));
debug(`checkRblStatus: ${domain} (error: ${error2.message}) (txtRecords: ${JSON.stringify(txtRecords)})`);
debug(`checkRblStatus: ${domain} (error: ${error2?.message || null}) (txtRecords: ${JSON.stringify(txtRecords)})`);
blacklistedServers.push(result);
}
@@ -590,7 +590,7 @@ async function getStatus(domain) {
for (let i = 0; i < checks.length; i++) {
const response = responses[i], check = checks[i];
if (response.status !== 'fulfilled') {
debug(`check ${check.what} was rejected. This is not expected`);
debug(`check ${check.what} was rejected. This is not expected. reason: ${response.reason}`);
continue;
}

View File

@@ -592,7 +592,7 @@ async function cleanupCerts(locations, auditSource, progressCallback) {
const certIds = await blobs.listCertIds();
const removedCertNames = [];
for (const certId of certIds) {
const certName = certId.match(new RegExp(`${blobs.CERT_PREFIX}-(.*).cert`))[0];
const certName = certId.match(new RegExp(`${blobs.CERT_PREFIX}-(.*).cert`))[1];
if (certNamesInUse.has(certName)) continue;
const cert = await blobs.getString(certId);

View File

@@ -454,6 +454,7 @@ async function copy(apiConfig, oldFilePath, newFilePath, progressCallback) {
}));
progressCallback({ message: `Copied ${total} files with error: ${copyError}` });
if (copyError) throw copyError;
}
async function remove(apiConfig, filename) {
@@ -560,7 +561,7 @@ async function testConfig(apiConfig) {
const putParams = {
Bucket: apiConfig.bucket,
Key: path.join(apiConfig.prefix, 'cloudron-testfile'),
Key: path.join(apiConfig.prefix, 'snapshot/cloudron-testfile'),
Body: 'testcontent'
};
@@ -568,9 +569,18 @@ async function testConfig(apiConfig) {
const [putError] = await safe(s3.putObject(putParams).promise());
if (putError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error put object cloudron-testfile. Message: ${putError.message} HTTP Code: ${putError.code}`);
const listParams = {
Bucket: apiConfig.bucket,
Prefix: path.join(apiConfig.prefix, 'snapshot'),
MaxKeys: 1
};
const [listError] = await safe(s3.listObjects(listParams).promise());
if (listError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects. Message: ${listError.message} HTTP Code: ${listError.code}`);
const delParams = {
Bucket: apiConfig.bucket,
Key: path.join(apiConfig.prefix, 'cloudron-testfile')
Key: path.join(apiConfig.prefix, 'snapshot/cloudron-testfile')
};
const [delError] = await safe(s3.deleteObject(delParams).promise());

View File

@@ -62,8 +62,10 @@ async function getDisks() {
const disks = {}; // by file system
let rootDisk;
const DISK_TYPES = [ 'ext4', 'xfs', 'cifs', 'nfs', 'fuse.sshfs' ]; // we don't show size of contents in untracked disk types
for (const disk of dfEntries) {
if (disk.type !== 'ext4' && disk.type !== 'xfs') continue;
if (!DISK_TYPES.includes(disk.type)) continue;
if (disk.mountpoint === '/') rootDisk = disk;
disks[disk.filesystem] = {
filesystem: disk.filesystem,
@@ -92,18 +94,21 @@ async function getDisks() {
const backupConfig = await settings.getBackupConfig();
if (backupConfig.provider === 'filesystem') {
const [, dfResult] = await safe(df.file(backupConfig.backupFolder));
disks[dfResult?.filesystem || rootDisk.filesystem].contents.push({ type: 'standard', id: 'cloudron-backup', path: backupConfig.backupFolder });
const filesystem = dfResult?.filesystem || rootDisk.filesystem;
if (disks[filesystem]) disks[filesystem].contents.push({ type: 'standard', id: 'cloudron-backup', path: backupConfig.backupFolder });
}
const [dockerError, dockerInfo] = await safe(docker.info());
if (!dockerError) {
const [, dfResult] = await safe(df.file(dockerInfo.DockerRootDir));
disks[dfResult?.filesystem || rootDisk.filesystem].contents.push({ type: 'standard', id: 'docker', path: dockerInfo.DockerRootDir });
const filesystem = dfResult?.filesystem || rootDisk.filesystem;
if (disks[filesystem]) disks[filesystem].contents.push({ type: 'standard', id: 'docker', path: dockerInfo.DockerRootDir });
}
for (const volume of await volumes.list()) {
const [, dfResult] = await safe(df.file(volume.hostPath));
disks[dfResult?.filesystem || rootDisk.filesystem].contents.push({ type: 'volume', id: volume.id, path: volume.hostPath });
const filesystem = dfResult?.filesystem || rootDisk.filesystem;
if (disks[filesystem]) disks[filesystem].contents.push({ type: 'volume', id: volume.id, path: volume.hostPath });
}
for (const app of await apps.list()) {
@@ -111,7 +116,8 @@ async function getDisks() {
const dataDir = await apps.getStorageDir(app);
const [, dfResult] = await safe(df.file(dataDir));
disks[dfResult?.filesystem || rootDisk.filesystem].contents.push({ type: 'app', id: app.id, path: dataDir });
const filesystem = dfResult?.filesystem || rootDisk.filesystem;
if (disks[filesystem]) disks[filesystem].contents.push({ type: 'app', id: app.id, path: dataDir });
}
const swaps = await getSwaps();
@@ -151,7 +157,7 @@ async function checkDiskSpace() {
async function getSwapSize() {
const swaps = await getSwaps();
return Object.keys(swaps).map(n => swaps[n].size).reduce((acc, cur) => acc + cur);
return Object.keys(swaps).map(n => swaps[n].size).reduce((acc, cur) => acc + cur, 0);
}
async function getMemory() {