1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-30 10:36:35 +02:00

Server: Allow creating a new user with no password, which must be set via email confirmation

This commit is contained in:
Laurent Cozic 2021-06-16 15:24:15 +01:00
parent ecd1602658
commit 18965494d9
4 changed files with 27 additions and 2 deletions

View File

@ -93,6 +93,7 @@ export default class UserModel extends BaseModel<User> {
if ('max_item_size' in object) user.max_item_size = object.max_item_size;
if ('can_share' in object) user.can_share = object.can_share;
if ('account_type' in object) user.account_type = object.account_type;
if ('must_set_password' in object) user.must_set_password = object.must_set_password;
return user;
}
@ -122,6 +123,7 @@ export default class UserModel extends BaseModel<User> {
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 ('can_share' in resource && !user.is_admin && resource.can_share !== previousResource.can_share) throw new ErrorForbidden('non-admin user cannot change can_share');
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');
}
if (action === AclAction.Delete) {
@ -174,7 +176,7 @@ export default class UserModel extends BaseModel<User> {
if (options.isNew) {
if (!user.email) throw new ErrorUnprocessableEntity('email must be set');
if (!user.password) throw new ErrorUnprocessableEntity('password must be set');
if (!user.password && !user.must_set_password) throw new ErrorUnprocessableEntity('password must be set');
} else {
if ('email' in user && !user.email) throw new ErrorUnprocessableEntity('email must be set');
if ('password' in user && !user.password) throw new ErrorUnprocessableEntity('password must be set');

View File

@ -85,6 +85,7 @@ describe('index_users', function() {
expect(!!newUser.is_admin).toBe(false);
expect(!!newUser.email).toBe(true);
expect(newUser.max_item_size).toBe(0);
expect(newUser.must_set_password).toBe(0);
const userModel = models().user();
const userFromModel: User = await userModel.load(newUser.id);
@ -93,6 +94,18 @@ describe('index_users', function() {
expect(userFromModel.password === '123456').toBe(false); // Password has been hashed
});
test('should ask user to set password if not set on creation', async function() {
const { session } = await createUserAndSession(1, true);
await postUser(session.id, 'test@example.com', '', {
max_item_size: '',
});
const newUser = await models().user().loadByEmail('test@example.com');
expect(newUser.must_set_password).toBe(1);
expect(!!newUser.password).toBe(true);
});
test('new user should be able to login', async function() {
const { session } = await createUserAndSession(1, true);

View File

@ -12,6 +12,7 @@ import { AclAction } from '../../models/BaseModel';
import { NotificationKey } from '../../models/NotificationModel';
import { formatBytes } from '../../utils/bytes';
import { accountTypeOptions, accountTypeProperties } from '../../models/UserModel';
import uuidgen from '../../utils/uuidgen';
interface CheckPasswordInput {
password: string;
@ -51,6 +52,11 @@ function makeUser(isNew: boolean, fields: any): User {
if (!isNew) user.id = fields.id;
if (isNew) {
user.must_set_password = user.password ? 0 : 1;
user.password = user.password ? user.password : uuidgen();
}
return user;
}

View File

@ -25,6 +25,7 @@
{{/accountTypes}}
</select>
</div>
<p class="help">If the account type is anything other than Default, the account-specific properties will be applied.</p>
</div>
{{/showAccountTypes}}
@ -52,7 +53,10 @@
<div class="control">
<input class="input" type="password" name="password2" autocomplete="new-password"/>
</div>
</div>
{{#global.owner.is_admin}}
<p class="help">When creating a new user, if no password is specified the user will have to set it by following the link in their email.</p>
{{/global.owner.is_admin}}
</div>
<div class="control">
<input type="submit" name="post_button" class="button is-primary" value="{{buttonTitle}}" />
{{#showDeleteButton}}