feat: Add verification to AccountStore

This commit is contained in:
Joachim Van Herwegen 2021-05-28 16:32:50 +02:00
parent 6214e0c537
commit 9bb42ddf0d
3 changed files with 30 additions and 0 deletions

View File

@ -19,6 +19,14 @@ export interface AccountStore {
*/
create: (email: string, webId: string, password: string) => Promise<void>;
/**
* Verifies the account creation. This can be used with, for example, e-mail verification.
* The account can only be used after it is verified.
* In case verification is not required, this should be called immediately after the `create` call.
* @param email - the account email
*/
verify: (email: string) => Promise<void>;
/**
* Changes the password
* @param email - the user's email

View File

@ -11,6 +11,7 @@ export interface AccountPayload {
webId: string;
email: string;
password: string;
verified: boolean;
}
/**
@ -72,6 +73,7 @@ export class BaseAccountStore implements AccountStore {
public async authenticate(email: string, password: string): Promise<string> {
const { account } = await this.getAccountPayload(email);
assert(account, 'No account by that email');
assert(account.verified, 'Account still needs to be verified');
assert(await compare(password, account.password), 'Incorrect password');
return account.webId;
}
@ -83,10 +85,18 @@ export class BaseAccountStore implements AccountStore {
email,
webId,
password: await hash(password, this.saltRounds),
verified: false,
};
await this.storage.set(key, payload);
}
public async verify(email: string): Promise<void> {
const { key, account } = await this.getAccountPayload(email);
assert(account, 'Account does not exist');
account.verified = true;
await this.storage.set(key, account);
}
public async changePassword(email: string, password: string): Promise<void> {
const { key, account } = await this.getAccountPayload(email);
assert(account, 'Account does not exist');

View File

@ -37,13 +37,24 @@ describe('A BaseAccountStore', (): void => {
await expect(store.authenticate(email, password)).rejects.toThrow('No account by that email');
});
it('errors when authenticating an unverified account.', async(): Promise<void> => {
await expect(store.create(email, webId, password)).resolves.toBeUndefined();
await expect(store.authenticate(email, 'wrongPassword')).rejects.toThrow('Account still needs to be verified');
});
it('errors when verifying a non-existent account.', async(): Promise<void> => {
await expect(store.verify(email)).rejects.toThrow('Account does not exist');
});
it('errors when authenticating with the wrong password.', async(): Promise<void> => {
await expect(store.create(email, webId, password)).resolves.toBeUndefined();
await expect(store.verify(email)).resolves.toBeUndefined();
await expect(store.authenticate(email, 'wrongPassword')).rejects.toThrow('Incorrect password');
});
it('can authenticate.', async(): Promise<void> => {
await expect(store.create(email, webId, password)).resolves.toBeUndefined();
await expect(store.verify(email)).resolves.toBeUndefined();
await expect(store.authenticate(email, password)).resolves.toBe(webId);
});
@ -54,6 +65,7 @@ describe('A BaseAccountStore', (): void => {
it('can change the password.', async(): Promise<void> => {
const newPassword = 'newPassword!';
await expect(store.create(email, webId, password)).resolves.toBeUndefined();
await expect(store.verify(email)).resolves.toBeUndefined();
await expect(store.changePassword(email, newPassword)).resolves.toBeUndefined();
await expect(store.authenticate(email, newPassword)).resolves.toBe(webId);
});