1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-14 18:27:44 +02:00

Server: Disallow changing email address until a secure solution to change it is implemented

This commit is contained in:
Laurent Cozic 2021-07-11 11:35:49 +01:00
parent 67a000add9
commit f8d2c26c8e
9 changed files with 34 additions and 13 deletions

View File

@ -40,6 +40,9 @@ export interface EnvVariables {
ACCOUNT_TYPES_ENABLED?: string;
ERROR_STACK_TRACES?: string;
SUPPORT_EMAIL?: string;
BUSINESS_EMAIL?: string;
}
let runningInDocker_: boolean = false;
@ -135,6 +138,7 @@ export async function initConfig(envType: Env, env: EnvVariables, overrides: any
const viewDir = `${rootDir}/src/views`;
const appPort = env.APP_PORT ? Number(env.APP_PORT) : 22300;
const baseUrl = baseUrlFromEnv(env, appPort);
const supportEmail = env.SUPPORT_EMAIL || 'admin@localhost';
config_ = {
appVersion: packageJson.version,
@ -156,6 +160,8 @@ export async function initConfig(envType: Env, env: EnvVariables, overrides: any
signupEnabled: env.SIGNUP_ENABLED === '1',
termsEnabled: env.TERMS_ENABLED === '1',
accountTypesEnabled: env.ACCOUNT_TYPES_ENABLED === '1',
supportEmail,
businessEmail: env.BUSINESS_EMAIL || supportEmail,
...overrides,
};
}

View File

@ -18,6 +18,7 @@ export default async function(ctx: AppContext) {
notifications: ctx.joplin.notifications || [],
hasNotifications: !!ctx.joplin.notifications && !!ctx.joplin.notifications.length,
owner: ctx.joplin.owner,
supportEmail: config().supportEmail,
});
} else {
ctx.response.status = 200;

View File

@ -132,15 +132,18 @@ export default class UserModel extends BaseModel<User> {
const previousResource = await this.load(resource.id);
if (!user.is_admin && resource.id !== user.id) throw new ErrorForbidden('non-admin user cannot modify another user');
if (!user.is_admin && 'is_admin' in resource) throw new ErrorForbidden('non-admin user cannot make themselves an admin');
if (user.is_admin && user.id === resource.id && 'is_admin' in resource && !resource.is_admin) throw new ErrorForbidden('admin user cannot make themselves a non-admin');
// TODO: Maybe define a whitelist of properties that can be changed
if ('max_item_size' in resource && !user.is_admin && resource.max_item_size !== previousResource.max_item_size) throw new ErrorForbidden('non-admin user cannot change max_item_size');
if ('max_total_item_size' in resource && !user.is_admin && resource.max_total_item_size !== previousResource.max_total_item_size) throw new ErrorForbidden('non-admin user cannot change max_total_item_size');
if ('can_share_folder' in resource && !user.is_admin && resource.can_share_folder !== previousResource.can_share_folder) throw new ErrorForbidden('non-admin user cannot change can_share_folder');
if ('account_type' in resource && !user.is_admin && resource.account_type !== previousResource.account_type) throw new ErrorForbidden('non-admin user cannot change account_type');
if ('must_set_password' in resource && !user.is_admin && resource.must_set_password !== previousResource.must_set_password) throw new ErrorForbidden('non-admin user cannot change must_set_password');
const canBeChangedByNonAdmin = [
'full_name',
'password',
];
for (const key of Object.keys(resource)) {
if (!user.is_admin && !canBeChangedByNonAdmin.includes(key) && (resource as any)[key] !== (previousResource as any)[key]) {
throw new ErrorForbidden(`non-admin user cannot change "${key}"`);
}
}
}
if (action === AclAction.Delete) {

View File

@ -3,6 +3,8 @@ import Router from '../../utils/Router';
import { RouteType } from '../../utils/types';
import { AppContext } from '../../utils/types';
import MarkdownIt = require('markdown-it');
import config from '../../config';
import markdownUtils from '@joplin/lib/markdownUtils';
const router: Router = new Router(RouteType.Web);
router.public = true;
@ -13,7 +15,7 @@ router.get('privacy', async (_path: SubPath, _ctx: AppContext) => {
## Who are we?
The Joplin Cloud web service is owned by Cozid Ltd, registered in England and Wales.
The Joplin Cloud web service is owned by Cozic Ltd, registered in England and Wales.
## What information do we collect?
@ -55,7 +57,7 @@ We keep your data for as long as you use the service. If you would like to stop
## How to contact us?
Please contact us at [team@joplincloud.com](mailto:team@joplincloud.com) for any question.`);
Please contact us at [${markdownUtils.escapeTitleText(config().supportEmail)}](mailto:${markdownUtils.escapeLinkUrl(config().supportEmail)}) for any question.`);
});
export default router;

View File

@ -3,6 +3,8 @@ import Router from '../../utils/Router';
import { RouteType } from '../../utils/types';
import { AppContext } from '../../utils/types';
import MarkdownIt = require('markdown-it');
import markdownUtils from '@joplin/lib/markdownUtils';
import config from '../../config';
const router: Router = new Router(RouteType.Web);
router.public = true;
@ -35,7 +37,7 @@ The use of this website is subject to the following terms of use:
- Your use of this website and any dispute arising out of such use of the website is subject to the laws of England, Northern Ireland, Scotland and Wales.
- Please contact us at [team@joplincloud.com](mailto:team@joplincloud.com) for any question.`);
- Please contact us at [${markdownUtils.escapeTitleText(config().supportEmail)}](mailto:${markdownUtils.escapeLinkUrl(config().supportEmail)}) for any question.`);
});
export default router;

View File

@ -163,9 +163,9 @@ describe('index/users', function() {
const userModel = models().user();
await patchUser(session.id, { id: user.id, email: 'test2@example.com' });
await patchUser(session.id, { id: user.id, full_name: 'new name' });
const modUser: User = await userModel.load(user.id);
expect(modUser.email).toBe('test2@example.com');
expect(modUser.full_name).toBe('new name');
});
test('should change the password', async function() {
@ -340,6 +340,9 @@ describe('index/users', function() {
// non-admin cannot change can_share_folder
await models().user().save({ id: user1.id, can_share_folder: 0 });
await expectHttpError(async () => patchUser(session1.id, { id: user1.id, can_share_folder: 1 }), ErrorForbidden.httpCode);
// non-admin cannot change non-whitelisted properties
await expectHttpError(async () => patchUser(session1.id, { id: user1.id, email: 'candothat@example.com' }), ErrorForbidden.httpCode);
});

View File

@ -36,6 +36,7 @@ interface GlobalParams {
privacyUrl?: string;
showErrorStackTraces?: boolean;
userDisplayName?: string;
supportEmail?: string;
}
export function isView(o: any): boolean {

View File

@ -109,6 +109,8 @@ export interface Config {
database: DatabaseConfig;
mailer: MailerConfig;
stripe: StripeConfig;
supportEmail: string;
businessEmail: string;
}
export enum HttpMethod {

View File

@ -11,8 +11,9 @@
<div class="field">
<label class="label">Email</label>
<div class="control">
<input class="input" type="email" name="email" value="{{user.email}}"/>
<input class="input" type="email" name="email" value="{{user.email}}" disabled/>
</div>
<p class="help">For security reasons the email cannot currently be changed. To request a change please contact {{global.supportEmail}}</p>
</div>
{{#global.owner.is_admin}}