You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.6 KiB
281 lines
7.6 KiB
// dtp-webapp-cli.js
|
|
// Copryright (C) 2022 DTP Technologies, LLC
|
|
// License: Apache-2.0
|
|
|
|
'use strict';
|
|
|
|
require('dotenv').config();
|
|
|
|
const path = require('path');
|
|
|
|
const mongoose = require('mongoose');
|
|
const generatePassword = require('password-generator');
|
|
|
|
const {
|
|
SitePlatform,
|
|
SiteAsync,
|
|
SiteLog,
|
|
} = require(path.join(__dirname, 'lib', 'site-lib'));
|
|
|
|
module.rootPath = __dirname;
|
|
module.pkg = require(path.join(module.rootPath, 'package.json'));
|
|
module.config = {
|
|
root: module.rootPath,
|
|
site: require(path.join(module.rootPath, 'config', 'site')),
|
|
http: require(path.join(module.rootPath, 'config', 'http')),
|
|
component: { logId: 'webapp-cli', index: 'webappCli', className: 'SampleAppCli' },
|
|
};
|
|
|
|
module.log = new SiteLog(module, module.config.component);
|
|
|
|
module.grantPermission = async (target, permission) => {
|
|
const User = mongoose.model('User');
|
|
try {
|
|
const user = await User.findOne({ email: target }).select('+permissions +flags');
|
|
if (!user) {
|
|
throw new Error(`User not found (email: ${target})`);
|
|
}
|
|
|
|
switch (permission) {
|
|
case 'admin':
|
|
user.flags.isAdmin = true;
|
|
break;
|
|
case 'moderator':
|
|
user.flags.isModerator = true;
|
|
break;
|
|
case 'login':
|
|
user.permissions.canLogin = true;
|
|
break;
|
|
default:
|
|
throw new Error(`Invalid permission: ${permission}`);
|
|
}
|
|
await user.save();
|
|
module.log.info('user updated', { user: user._id });
|
|
} catch (error) {
|
|
module.log.error('failed to grant permission', { app: module.app, target, permission, error });
|
|
}
|
|
};
|
|
|
|
module.revokePermission = async (target, permission) => {
|
|
const User = mongoose.model('User');
|
|
try {
|
|
const user = await User.findOne({ email: target }).select('+permissions +flags');
|
|
switch (permission) {
|
|
case 'admin':
|
|
user.flags.isAdmin = false;
|
|
break;
|
|
case 'moderator':
|
|
user.flags.isModerator = false;
|
|
break;
|
|
case 'login':
|
|
user.permissions.canLogin = false;
|
|
break;
|
|
default:
|
|
throw new Error(`Invalid permission: ${permission}`);
|
|
}
|
|
await user.save();
|
|
module.log.info('user updated', { user: user._id });
|
|
} catch (error) {
|
|
module.log.error('failed to revoke permission', { app: module.app, target, permission, error });
|
|
}
|
|
};
|
|
|
|
module.deleteOtpAccount = async (target) => {
|
|
const { otpAuth: otpAuthService } = module.services;
|
|
const User = mongoose.model('User');
|
|
try {
|
|
const user = await User.findOne({ email: target }).lean();
|
|
const response = await otpAuthService.removeForUser(user);
|
|
module.log.info('OTP accounts removed', { userId: user._id, response });
|
|
} catch (error) {
|
|
module.log.error('failed to remove OTP account', { target, error });
|
|
}
|
|
};
|
|
|
|
module.makeBucket = async (target) => {
|
|
const { minio: minioService } = module.services;
|
|
try {
|
|
module.log.info('creating bucket', { target });
|
|
await minioService.makeBucket(target, 'us-east-1');
|
|
} catch (error) {
|
|
module.log.error('failed to create bucket', { target, error });
|
|
}
|
|
};
|
|
|
|
module.resetIndexes = async ( ) => {
|
|
try {
|
|
module.log.info('resetting MongoDB indexes...');
|
|
await SitePlatform.resetIndexes(module);
|
|
} catch (error) {
|
|
module.log.error('failed to reset database indexes', { error });
|
|
}
|
|
};
|
|
|
|
module.resetPassword = async (username) => {
|
|
const { user: userService } = module.services;
|
|
const User = mongoose.model('User');
|
|
|
|
const user = await User
|
|
.findOne({
|
|
username_lc: username.trim().toLowerCase(),
|
|
})
|
|
.lean();
|
|
|
|
if (!user) {
|
|
throw new Error('user not found');
|
|
}
|
|
|
|
const password = generatePassword(8, true);
|
|
module.log.info('updating user password', { username, password });
|
|
await userService.updatePassword(user, password);
|
|
};
|
|
|
|
module.sendWelcomeEmail = async (username) => {
|
|
const User = mongoose.model('User');
|
|
|
|
if (username === 'all') {
|
|
await User
|
|
.find()
|
|
.select('+flags +optIn')
|
|
.cursor()
|
|
.eachAsync(module.sendUserWelcomeEmail, 4);
|
|
} else {
|
|
const user = await User
|
|
.findOne({
|
|
username_lc: username.trim().toLowerCase(),
|
|
})
|
|
.select('+flags +optIn')
|
|
.lean();
|
|
if (!user) {
|
|
throw new Error('user not found');
|
|
}
|
|
await module.sendUserWelcomeEmail(user);
|
|
}
|
|
};
|
|
|
|
module.sendUserWelcomeEmail = async (user) => {
|
|
const { user: userService } = module.services;
|
|
|
|
if (user.flags.isEmailVerified) {
|
|
module.log.alert('user is email-verified (aboring welcome email)', {
|
|
user: user._id,
|
|
username: user.username,
|
|
});
|
|
return;
|
|
}
|
|
|
|
module.log.info('sending welcome email', {
|
|
user: user._id,
|
|
username: user.username,
|
|
email: user.email,
|
|
});
|
|
await userService.sendWelcomeEmail(user);
|
|
};
|
|
|
|
module.requestConstellationConnect = async (host) => {
|
|
const { coreNode: coreNodeService } = module.services;
|
|
const { core, networkPolicy } = await coreNodeService.resolveCore(host);
|
|
module.log.info('Constellation Connect is not implemented', { core, networkPolicy });
|
|
};
|
|
|
|
module.requestCoreConnect = async (host) => {
|
|
const { coreNode: coreNodeService } = module.services;
|
|
const { core, networkPolicy } = await coreNodeService.resolveCore(host);
|
|
module.log.info('sending Core connection request', { core, networkPolicy });
|
|
|
|
const txConnect = await coreNodeService.sendRequest(core, {
|
|
method: 'POST',
|
|
url: '/core/connect',
|
|
body: {
|
|
version: module.pkg.version,
|
|
site: module.config.site,
|
|
},
|
|
});
|
|
|
|
module.log.info('connect tranaction', { txConnect });
|
|
};
|
|
|
|
/*
|
|
* SERVER INIT
|
|
*/
|
|
|
|
(async ( ) => {
|
|
|
|
const argv = require('argv'); // https://www.npmjs.com/package/argv
|
|
argv.version(module.pkg.version);
|
|
argv.option([
|
|
{
|
|
name: 'action',
|
|
short: 'a',
|
|
type: 'string',
|
|
description: 'The action to perform',
|
|
example: 'dtp-webapp-cli --action=grant --permission=moderator email email ...',
|
|
},
|
|
{
|
|
name: 'permission',
|
|
short: 'p',
|
|
type: 'string',
|
|
description: 'The permission(s) being added or removed',
|
|
example: 'dtp-webapp-cli --action=grant --permission=admin email email ...'
|
|
},
|
|
]);
|
|
|
|
try {
|
|
await SitePlatform.startPlatform(module);
|
|
} catch (error) {
|
|
module.log.error(`failed to start DTP ${module.config.component.className} platform`, { error });
|
|
return;
|
|
}
|
|
|
|
try {
|
|
module.app = argv.run();
|
|
|
|
await SiteAsync.each(module.app.targets, async (target) => {
|
|
module.log.info('processing target', { target });
|
|
switch (module.app.options.action) {
|
|
case 'grant':
|
|
await module.grantPermission(target, module.app.options.permission);
|
|
break;
|
|
|
|
case 'revoke':
|
|
await module.revokePermission(target, module.app.options.permission);
|
|
break;
|
|
|
|
case 'make-bucket':
|
|
await module.makeBucket(target);
|
|
break;
|
|
|
|
case 'core-connect':
|
|
await module.requestCoreConnect(target);
|
|
break;
|
|
|
|
case 'constellation-connect':
|
|
await module.requestConstellationConnect(target);
|
|
break;
|
|
|
|
case 'delete-otp':
|
|
await module.deleteOtpAccount(target);
|
|
break;
|
|
|
|
case 'reset-password':
|
|
await module.resetPassword(target);
|
|
break;
|
|
|
|
case 'reset-indexes':
|
|
await module.resetIndexes();
|
|
break;
|
|
|
|
case 'welcome-email':
|
|
await module.sendWelcomeEmail(target);
|
|
break;
|
|
|
|
default:
|
|
throw new Error(`invalid action: ${module.app.options.action}`);
|
|
}
|
|
});
|
|
process.exit(0);
|
|
} catch (error) {
|
|
module.log.error('failed to process target', { app: module.app, error });
|
|
}
|
|
|
|
})();
|