// dtp-webapp-cli.js
// Copryright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0
'use strict' ;
const DTP_COMPONENT = { name : 'Sample App CLI' , slug : 'webapp-cli' } ;
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 = {
component : DTP_COMPONENT ,
root : module . rootPath ,
site : require ( path . join ( module . rootPath , 'config' , 'site' ) ) ,
http : require ( path . join ( module . rootPath , 'config' , 'http' ) ) ,
} ;
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' ) ;
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 . slug } 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 } ) ;
}
} ) ( ) ;