Use userId instead of username & simple server test

This commit is contained in:
Jan Dvorak
2022-03-20 18:51:06 +01:00
parent d88520469f
commit 70e60fe485
5 changed files with 64 additions and 28 deletions

View File

@@ -2,6 +2,7 @@ import { Accounts } from 'meteor/accounts-base';
import twofactor from 'node-2fa';
import QRCode from 'qrcode-svg';
import { Meteor } from 'meteor/meteor';
import { check, Match } from 'meteor/check';
Accounts._is2faEnabledForUser = selector => {
if (!Meteor.isServer) {
@@ -13,7 +14,7 @@ Accounts._is2faEnabledForUser = selector => {
if (typeof selector === 'string') {
if (!selector.includes('@')) {
selector = { username: selector };
selector = { $or: [{ _id: selector }, { username: selector }] };
} else {
selector = { email: selector };
}
@@ -21,7 +22,7 @@ Accounts._is2faEnabledForUser = selector => {
const user = Meteor.users.findOne(selector) || {};
const { services: { twoFactorAuthentication } = {} } = user;
return (
return !!(
twoFactorAuthentication &&
twoFactorAuthentication.secret &&
twoFactorAuthentication.type === 'otp'
@@ -43,6 +44,7 @@ Accounts._isTokenValid = (secret, code) => {
Meteor.methods({
generate2faActivationQrCode(appName) {
check(appName, String);
const user = Meteor.user();
if (!user) {
@@ -52,28 +54,27 @@ Meteor.methods({
);
}
const { username } = user;
const { secret, uri } = twofactor.generateSecret({
name: appName.trim(),
account: username,
account: user.username || user._id
});
const svg = new QRCode(uri).svg();
Meteor.users.update(
{ username },
{ _id: user._id },
{
$set: {
'services.twoFactorAuthentication': {
secret,
},
},
secret
}
}
}
);
return svg;
},
enableUser2fa(code) {
check(code, String);
const user = Meteor.user();
if (!user) {
@@ -81,8 +82,7 @@ Meteor.methods({
}
const {
services: { twoFactorAuthentication },
username,
services: { twoFactorAuthentication }
} = user;
if (!twoFactorAuthentication || !twoFactorAuthentication.secret) {
@@ -96,37 +96,44 @@ Meteor.methods({
}
Meteor.users.update(
{ username },
{ _id: user._id },
{
$set: {
'services.twoFactorAuthentication': {
...twoFactorAuthentication,
type: 'otp',
},
},
type: 'otp'
}
}
}
);
},
disableUser2fa() {
const user = Meteor.user();
const userId = Meteor.userId();
if (!user) {
if (!userId) {
throw new Meteor.Error(400, 'No user logged in.');
}
Meteor.users.update(
{ username: user.username },
{ _id: userId },
{
$unset: {
'services.twoFactorAuthentication': 1,
},
'services.twoFactorAuthentication': 1
}
}
);
},
has2faEnabled(selector) {
if (!Meteor.user()) {
check(selector, Match.Maybe(Match.OneOf(String, Object)));
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error(400, 'No user logged in.');
}
if (!selector) {
selector = { $or: [{ _id: userId }, { username: userId }] };
}
return Accounts._is2faEnabledForUser(selector);
},
}
});

View File

@@ -12,11 +12,25 @@ Npm.depends({
Package.onUse(function(api) {
api.use(['accounts-base'], ['client', 'server']);
// Export Accounts (etc) to packages using this one.
// Export Accounts (etc.) to packages using this one.
api.imply('accounts-base', ['client', 'server']);
api.use('ecmascript');
api.use('check', 'server');
api.addFiles(['2fa-client.js'], 'client');
api.addFiles(['2fa-server.js'], 'server');
});
Package.onTest(function(api) {
api.use([
'accounts-base',
'accounts-password',
'ecmascript',
'tinytest',
'random',
'accounts-2fa',
]);
api.mainModule('server_tests.js', 'server');
});

View File

@@ -0,0 +1,15 @@
import { Accounts } from 'meteor/accounts-base';
import { Random } from 'meteor/random';
Tinytest.add('account - 2fa - has2faEnabled', test => {
// Create users
const userWithout2FA = Accounts.insertUserDoc({}, { emails: [{address: `${Random.id()}@meteorapp.com`, verified: true}] });
const userWith2FA = Accounts.insertUserDoc({}, { emails: [{address: `${Random.id()}@meteorapp.com`, verified: true}], services: { twoFactorAuthentication: { type: 'otp', secret: 'superSecret' } } });
test.equal(Accounts._is2faEnabledForUser(userWithout2FA), false);
test.equal(Accounts._is2faEnabledForUser(userWith2FA), true);
// cleanup
Accounts.users.remove(userWithout2FA);
Accounts.users.remove(userWith2FA);
});

View File

@@ -10,7 +10,7 @@ const profile = {
name: username,
[excludeField]: excludeValue,
[defaultExcludeField]: excludeValue,
}
};
const logoutAndCreateUser = (test, done, nextTests) => {
Meteor.logout(() => {

View File

@@ -114,7 +114,7 @@ export const Match = {
_failIfArgumentsAreNotAllChecked(f, context, args, description) {
const argChecker = new ArgumentChecker(args, description);
const result = currentArgumentChecker.withValue(
argChecker,
argChecker,
() => f.apply(context, args)
);
@@ -261,7 +261,7 @@ const testSubtree = (value, pattern) => {
if (typeof value === 'number' && (value | 0) === value) {
return false;
}
return {
message: `Expected Integer, got ${stringForErrorMessage(value)}`,
path: '',
@@ -296,7 +296,7 @@ const testSubtree = (value, pattern) => {
return result;
}
}
return false;
}
@@ -310,7 +310,7 @@ const testSubtree = (value, pattern) => {
if (!(err instanceof Match.Error)) {
throw err;
}
return {
message: err.message,
path: err.path