Compare commits

...

17 commits

Author SHA1 Message Date
Johannes Zellner de786e59ed Bump version 2024-02-23 16:57:55 +01:00
Johannes Zellner 0c77e8c32a Update for closed regsitration release 2024-02-23 16:45:18 +01:00
Johannes Zellner 6fa11cf195 Update test deps 2024-02-23 15:38:53 +01:00
Johannes Zellner b72b058f5e Update to 4.2.8 2024-02-23 15:38:34 +01:00
Johannes Zellner 77f9fa9a63 Bump version 2024-02-16 13:33:45 +01:00
Johannes Zellner 56bcb395dc Update test deps 2024-02-16 13:19:30 +01:00
Johannes Zellner a24ad995de Update to 4.2.7 2024-02-16 13:19:22 +01:00
Vladimir D f8c84b6ef5 migrateUsers.js: logic updated to resume if failed 2024-02-15 20:46:05 +04:00
Vladimir D a08af787d7 migrateUsers.js updated to use username instead of email 2024-02-15 17:18:05 +04:00
Vladimir D e556c856f1 migrate LDAP users to OIDC 2024-02-15 15:50:03 +04:00
Johannes Zellner 25292a86b4 Make tests language independent 2024-02-14 18:05:43 +01:00
Vladimir D 146b5ac17e OIDC auth implemented, tests updated 2024-02-14 18:05:43 +01:00
Johannes Zellner fdc4e20c77 Bump version 2024-02-14 18:05:43 +01:00
Johannes Zellner 886f27ec9a Update to 4.2.6 2024-02-14 18:02:59 +01:00
Johannes Zellner 941292bf52 Bump version 2024-02-01 17:29:01 +01:00
Johannes Zellner b4f7038f79 Update test deps 2024-02-01 17:07:25 +01:00
Johannes Zellner b77a74978c Update to 4.2.5 2024-02-01 17:07:16 +01:00
9 changed files with 735 additions and 141 deletions

View file

@ -433,3 +433,41 @@
* Fix RecordNotUnique errors in LinkCrawlWorker (tribela)
* Fix Mastodon not correctly processing HTTP Signatures with query strings (ClearlyClaire, ClearlyClaire)
[1.12.5]
* Update Mastodon to 4.2.5
* [Full changelog](https://github.com/mastodon/mastodon/releases/tag/v4.2.5)
* Fix insufficient origin validation (CVE-2024-23832, GHSA-3fjr-858r-92rw)
[1.12.6]
* Update Mastodon to 4.2.6
* This release is an important security release fixing several security issue.
* [Full changelog](https://github.com/mastodon/mastodon/releases/tag/v4.2.6)
* Change external authentication behavior to never reattach a new identity to an existing user by default (GHSA-vm39-j3vx-pch3)
* Update the nokogiri dependency (see GHSA-xc9x-jj77-9p9j)
* Disable administrative Doorkeeper routes (ThisIsMissEm)
* Fix ongoing streaming sessions not being invalidated when applications get deleted in some cases (GHSA-7w3c-p9j8-mq3x)
* Update the sidekiq-unique-jobs dependency (see GHSA-cmh9-rx85-xj38)
[1.13.0]
* Update Mastodon to 4.2.7
* This release is an important security release fixing several security issue.
* With this package release, the app moves from LDAP authentication to OpenID Connect
* [Full changelog](https://github.com/mastodon/mastodon/releases/tag/v4.2.7)
* Fix OmniAuth tests and edge cases in error handling (ClearlyClaire, ClearlyClaire)
* Fix new installs by upgrading to the latest release of the nsa gem, instead of a no longer existing commit (mjankowski)
* Fix insufficient checking of remote posts (GHSA-jhrq-qvrm-qr36)
[1.13.1]
* Update Mastodon to 4.2.8
* This update changes registrations to be closed by default.
* [Full changelog](https://github.com/mastodon/mastodon/releases/tag/v4.2.8)
* Add hourly task to automatically require approval for new registrations in the absence of moderators (ClearlyClaire, ClearlyClaire)
* In order to prevent future abandoned Mastodon servers from being used for spam, harassment and other malicious activity, Mastodon will now automatically switch new user registrations to require moderator approval whenever they are left open and no activity (including non-moderation actions from apps) from any logged-in user with permission to access moderation reports has been detected in a full week.
* When this happens, users with the permission to change server settings will receive an email notification.
* This feature is disabled when EMAIL_DOMAIN_ALLOWLIST is used, and can also be disabled with DISABLE_AUTOMATIC_SWITCHING_TO_APPROVED_REGISTRATIONS=true.
* Change registrations to be closed by default on new installations (ClearlyClaire)
* If you are running a server and never changed your registrations mode from the default, updating will automatically close your registrations.
* Simply re-enable them through the administration interface or using tootctl settings registrations open if you want to enable them again.
* Fix processing of remote ActivityPub actors making use of Link objects as Image url (ClearlyClaire)
* Fix link verifications when page size exceeds 1MB (ClearlyClaire)

View file

@ -5,8 +5,8 @@
"description": "file://DESCRIPTION.md",
"changelog": "file://CHANGELOG",
"tagline": "Federated social network",
"version": "1.12.4",
"upstreamVersion": "4.2.4",
"version": "1.13.1",
"upstreamVersion": "4.2.8",
"healthCheckPath": "/about",
"httpPort": 8000,
"memoryLimit": 1610612736,
@ -16,7 +16,7 @@
"postgresql": {},
"redis": {},
"sendmail": {},
"ldap": {},
"oidc": { "loginRedirectUri": "/auth/auth/openid_connect/callback" },
"scheduler": {
"cleanup": {
"schedule": "11 01 * * *",

View file

@ -33,7 +33,7 @@ RUN gem install --no-document bundler
ENV RAILS_ENV production
ENV NODE_ENV production
ARG VERSION=4.2.4
ARG VERSION=4.2.8
RUN curl -L https://github.com/tootsuite/mastodon/archive/v${VERSION}.tar.gz | tar -xz --strip-components 1 -f - && \
bundle config --local set deployment 'true' && \

View file

@ -1,4 +1,6 @@
Accounts are created with the username and the subdomain under which this app is installed e.g. `@$CLOUDRON-USERNAME@$CLOUDRON-APP-FQDN`. Mastodon does not allow changing the domain part of the account later. See [the docs](https://docs.cloudron.io/apps/mastodon/#federation) for more information, if you want to change this domain.
Accounts are created with the username and the subdomain under which this app is installed e.g. `@$CLOUDRON-USERNAME@$CLOUDRON-APP-FQDN`.
Mastodon does not allow changing the domain part of the account later.
See [the docs](https://docs.cloudron.io/apps/mastodon/#federation) for more information, f you want to change this domain.
<sso>
**NOTE:**
@ -7,3 +9,9 @@ Accounts are created with the username and the subdomain under which this app is
* External registration [does not work well](https://github.com/mastodon/mastodon/issues/20655) when Cloudron user management is enabled.
</sso>
<nosso>
**NOTE:**
* Open registration is disabled by default. To enable this, see the [docs](https://docs.cloudron.io/apps/mastodon/#registration)
* To add an initial account follow those [instructions](https://docs.cloudron.io/apps/mastodon/#adding-users)
</nosso>

View file

@ -32,15 +32,15 @@ SMTP_AUTH_METHOD=plain
SMTP_OPENSSL_VERIFY_MODE=none
# SSO configuration
LDAP_ENABLED=
LDAP_HOST=
LDAP_PORT=
LDAP_BASE=
LDAP_BIND_DN=
LDAP_PASSWORD=
LDAP_UID=username
LDAP_SEARCH_FILTER=(|(%{uid}=%{email})(mail=%{email}))
LDAP_METHOD=plain
OIDC_ENABLED=
OIDC_DISPLAY_NAME=
OIDC_ISSUER=
OIDC_CLIENT_ID=
OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URI=
OIDC_DISCOVERY=
OIDC_SCOPE=
OIDC_UID_FIELD=
# Application secrets
SECRET_KEY_BASE=

View file

@ -30,16 +30,19 @@ sed -e "s/DB_HOST=.*/DB_HOST=${CLOUDRON_POSTGRESQL_HOST}/g" \
-e "s/WEB_DOMAIN=.*/WEB_DOMAIN=${CLOUDRON_APP_DOMAIN}/g" \
-i /app/data/env.production
if [[ -n "${CLOUDRON_LDAP_SERVER:-}" ]]; then
sed -e "s/LDAP_ENABLED=.*/LDAP_ENABLED=true/g" \
-e "s/LDAP_HOST=.*/LDAP_HOST=${CLOUDRON_LDAP_SERVER}/g" \
-e "s/LDAP_PORT=.*/LDAP_PORT=${CLOUDRON_LDAP_PORT}/g" \
-e "s/LDAP_BASE=.*/LDAP_BASE=${CLOUDRON_LDAP_USERS_BASE_DN}/g" \
-e "s/LDAP_BIND_DN=.*/LDAP_BIND_DN=${CLOUDRON_LDAP_BIND_DN}/g" \
-e "s/LDAP_PASSWORD=.*/LDAP_PASSWORD=${CLOUDRON_LDAP_BIND_PASSWORD}/g" \
if [[ -n "${CLOUDRON_OIDC_ISSUER:-}" ]]; then
echo "==> Setting up OIDC"
sed -e "s/OIDC_ENABLED=.*/OIDC_ENABLED=true/g" \
-e "s/OIDC_DISPLAY_NAME=.*/OIDC_DISPLAY_NAME=Cloudron/g" \
-e "s/OIDC_ISSUER=.*/OIDC_ISSUER=${CLOUDRON_OIDC_ISSUER//\//\\\/}/g" \
-e "s/OIDC_CLIENT_ID=.*/OIDC_CLIENT_ID=${CLOUDRON_OIDC_CLIENT_ID}/g" \
-e "s/OIDC_CLIENT_SECRET=.*/OIDC_CLIENT_SECRET=${CLOUDRON_OIDC_CLIENT_SECRET}/g" \
-e "s/OIDC_REDIRECT_URI=.*/OIDC_REDIRECT_URI=${CLOUDRON_APP_ORIGIN//\//\\\/}\/auth\/auth\/openid_connect\/callback/g" \
-e "s/OIDC_DISCOVERY=.*/OIDC_DISCOVERY=true/g" \
-e "s/OIDC_SCOPE=.*/OIDC_SCOPE=openid,profile,email/g" \
-e "s/OIDC_UID_FIELD=.*/OIDC_UID_FIELD=sub/g" \
-e "s/OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED=.*/OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true/g" \
-i /app/data/env.production
else
sed -e "s/LDAP_ENABLED=.*/LDAP_ENABLED=false/g" -i /app/data/env.production
fi
rm -f /run/mastodon/Gemfile.lock && cp /app/code/Gemfile.lock.original /run/mastodon/Gemfile.lock
@ -57,7 +60,7 @@ if grep -q "^SECRET_KEY_BASE=$" /app/data/env.production; then
echo "==> Init database"
HOME=/app/data SAFETY_ASSURED=1 bundle exec rails db:schema:load db:seed
if [[ -n "${CLOUDRON_LDAP_SERVER:-}" ]]; then
if [[ -n "${CLOUDRON_OIDC_ISSUER:-}" ]]; then
echo "Disabling registration by default"
PGPASSWORD=${CLOUDRON_POSTGRESQL_PASSWORD} psql -h ${CLOUDRON_POSTGRESQL_HOST} -p ${CLOUDRON_POSTGRESQL_PORT} -U ${CLOUDRON_POSTGRESQL_USERNAME} -d ${CLOUDRON_POSTGRESQL_DATABASE} \
-c "INSERT INTO settings (var, value) VALUES ('registrations_mode', 'none')"

656
test/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,10 +10,10 @@
"license": "ISC",
"devDependencies": {
"expect.js": "^0.3.1",
"mocha": "^10.2.0",
"selenium-webdriver": "^4.17.0"
"mocha": "^10.3.0",
"selenium-webdriver": "^4.18.1"
},
"dependencies": {
"chromedriver": "^120.0.2"
"chromedriver": "^122.0.3"
}
}

View file

@ -30,6 +30,7 @@ describe('Application life cycle test', function () {
const EXEC_ARGS = { cwd: path.resolve(__dirname, '..'), stdio: 'inherit' };
let browser, app;
var athenticated_by_oidc = false;
let username = process.env.USERNAME;
let password = process.env.PASSWORD;
let manifest = require('../CloudronManifest.json');
@ -42,6 +43,15 @@ describe('Application life cycle test', function () {
browser.quit();
});
function sleep(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
async function waitForElement(elem) {
await browser.wait(until.elementLocated(elem), TEST_TIMEOUT);
await browser.wait(until.elementIsVisible(browser.findElement(elem)), TEST_TIMEOUT);
}
async function exists(selector) {
await browser.wait(until.elementLocated(selector), TEST_TIMEOUT);
}
@ -55,7 +65,7 @@ describe('Application life cycle test', function () {
if (mode === 'none') {
await browser.get('https://' + app.fqdn);
await browser.sleep(2000);
await browser.findElement(By.xpath('//div[@class="sign-in-banner"]/descendant::button/span[contains(text(), "Create account")]')).click();
await browser.findElement(By.xpath('//div[@class="sign-in-banner"]/descendant::button/span[contains(text(), "Create account")] | //div[@class="sign-in-banner"]/descendant::a/span[contains(text(), "Create account")]')).click();
await visible(By.xpath('//span[contains(text()[2], "is currently not possible")]'));
} else if (mode === 'open') {
await browser.get('https://' + app.fqdn + '/auth/sign_up');
@ -72,6 +82,28 @@ describe('Application life cycle test', function () {
await browser.sleep(3000); // can be wizard or timeline at this point
}
async function loginOIDC(username, password) {
browser.manage().deleteAllCookies();
await browser.get(`https://${app.fqdn}/auth/sign_in`);
await browser.sleep(4000);
await browser.findElement(By.xpath('//a[contains(@class, "button") and text()="Cloudron"]')).click();
await browser.sleep(4000);
if (!athenticated_by_oidc) {
await waitForElement(By.xpath('//input[@name="username"]'));
await browser.findElement(By.xpath('//input[@name="username"]')).sendKeys(username);
await browser.findElement(By.xpath('//input[@name="password"]')).sendKeys(password);
await browser.sleep(2000);
await browser.findElement(By.id('loginSubmitButton')).click();
await browser.sleep(2000);
athenticated_by_oidc = true;
}
await waitForElement(By.xpath('//a[contains(., "Edit profile")] | //strong[text()="Successfully authenticated from Cloudron account."]'));
}
async function logout() {
await browser.get('https://' + app.fqdn + '/settings/preferences/appearance'); // there is also separate login page at /users/sign_in
await browser.wait(until.elementLocated(By.id('logout')), TEST_TIMEOUT);
@ -97,49 +129,12 @@ describe('Application life cycle test', function () {
}
xit('build app', function () { execSync('cloudron build', EXEC_ARGS); });
it('install app', function () { execSync('cloudron install --location ' + LOCATION, EXEC_ARGS); });
it('can get app information', getAppInfo);
it('registration is disabled', checkRegistration.bind(null, 'none'));
it('can LDAP login', login.bind(null, username, password));
it('can dismiss help', dismissHelp);
it('can see timeline', checkTimeline);
it('can logout', logout);
it('backup app', function () { execSync('cloudron backup create --app ' + app.id, EXEC_ARGS); });
it('restore app', function () {
const backups = JSON.parse(execSync('cloudron backup list --raw'));
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
execSync('cloudron install --location ' + LOCATION, EXEC_ARGS);
getAppInfo();
execSync(`cloudron restore --backup ${backups[0].id} --app ${app.id}`, EXEC_ARGS);
});
it('can LDAP login', login.bind(null, username, password));
it('can see timeline', checkTimeline);
it('can restart app', function () { execSync('cloudron restart --app ' + app.id, EXEC_ARGS); });
it('can see timeline', checkTimeline);
it('move to different location', async function () {
await browser.get('about:blank');
execSync('cloudron configure --location ' + LOCATION + '2 --app ' + app.id, EXEC_ARGS);
});
it('can get app information', getAppInfo);
it('can LDAP login', login.bind(null, username, password));
it('can see timeline', checkTimeline);
it('uninstall app', async function () {
await browser.get('about:blank');
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
});
// No SSO
it('install app (no sso)', function () { execSync('cloudron install --no-sso --location ' + LOCATION, EXEC_ARGS); });
it('can get app information', getAppInfo);
it('has registration open', checkRegistration.bind(null, 'open'));
it('has registration open', checkRegistration.bind(null, 'none'));
let testPassword;
it('create a user with CLI', function () {
let output = execSync('cloudron exec --app ' + LOCATION + ' -- bin/tootctl accounts create test --email=test@cloudron.io', { cwd: path.resolve(__dirname, '..'), encoding: 'utf8' });
@ -161,10 +156,50 @@ describe('Application life cycle test', function () {
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
});
// SSO
it('install app (sso)', function () { execSync('cloudron install --location ' + LOCATION, EXEC_ARGS); });
it('can get app information', getAppInfo);
it('registration is disabled', checkRegistration.bind(null, 'none'));
it('can OIDC login', loginOIDC.bind(null, username, password));
it('can dismiss help', dismissHelp);
it('can see timeline', checkTimeline);
it('can logout', logout);
it('backup app', function () { execSync('cloudron backup create --app ' + app.id, EXEC_ARGS); });
it('restore app', function () {
const backups = JSON.parse(execSync('cloudron backup list --raw'));
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
execSync('cloudron install --location ' + LOCATION, EXEC_ARGS);
getAppInfo();
execSync(`cloudron restore --backup ${backups[0].id} --app ${app.id}`, EXEC_ARGS);
});
it('can OIDC login', loginOIDC.bind(null, username, password));
it('can see timeline', checkTimeline);
it('can restart app', function () { execSync('cloudron restart --app ' + app.id, EXEC_ARGS); });
it('can see timeline', checkTimeline);
it('move to different location', async function () {
await browser.get('about:blank');
execSync('cloudron configure --location ' + LOCATION + '2 --app ' + app.id, EXEC_ARGS);
});
it('can get app information', getAppInfo);
it('can OIDC login', loginOIDC.bind(null, username, password));
it('can see timeline', checkTimeline);
it('uninstall app', async function () {
await browser.get('about:blank');
execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS);
});
// test update
it('can install app', function () { execSync('cloudron install --appstore-id ' + manifest.id + ' --location ' + LOCATION, EXEC_ARGS); });
it('can get app information', getAppInfo);
it('can LDAP login', login.bind(null, username, password));
// needs to be changed to loginOIDC on the next release
it('can OIDC login', loginOIDC.bind(null, username, password));
it('can logout', logout);
it('can update', async function () {
@ -172,7 +207,7 @@ describe('Application life cycle test', function () {
execSync('cloudron update --app ' + LOCATION, EXEC_ARGS);
});
it('can LDAP login', login.bind(null, username, password));
it('can OIDC login', loginOIDC.bind(null, username, password));
it('uninstall app', function () { execSync('cloudron uninstall --app ' + app.id, EXEC_ARGS); });
});