mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Use userId instead of username & simple server test
This commit is contained in:
@@ -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);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
15
packages/accounts-2fa/server_tests.js
Normal file
15
packages/accounts-2fa/server_tests.js
Normal 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);
|
||||
});
|
||||
@@ -10,7 +10,7 @@ const profile = {
|
||||
name: username,
|
||||
[excludeField]: excludeValue,
|
||||
[defaultExcludeField]: excludeValue,
|
||||
}
|
||||
};
|
||||
|
||||
const logoutAndCreateUser = (test, done, nextTests) => {
|
||||
Meteor.logout(() => {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user