feat: usermod command

merge-requests/6/head
Hiroyuki 2021-09-11 16:38:35 -04:00
parent b40b39ca12
commit 64a68e51a3
No known key found for this signature in database
GPG Key ID: AF65958B7B7362E6
8 changed files with 89 additions and 16 deletions

View File

@ -39,6 +39,7 @@
"import/prefer-default-export": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": 2,
"import/extensions": "off"
"import/extensions": "off",
"consistent-return": "off"
}
}

View File

@ -4,6 +4,8 @@ import { randomBytes } from 'crypto';
import { AccountInterface } from '../models';
import { Client } from '..';
export const LINUX_USERNAME_REGEX = /^[a-z][-a-z0-9]*$/;
export default class AccountUtil {
public client: Client;

View File

@ -311,16 +311,9 @@ export default class Util {
return Promise.resolve(log);
}
public getAcctHash(userpath: string) {
try {
return fs.readFileSync(`${userpath}/.securesign/auth`).toString();
} catch (error) {
return null;
}
}
public parseCertificate(pem: string) {
return axios.post<Certificate>('https://certapi.libraryofcode.org/parse', pem);
return axios.post<Certificate>('https://certapi.libraryofcode.org/parse', pem)
.then((response) => response.data);
}
public upload(text: string, extension = 'txt') {

View File

@ -1,5 +1,6 @@
import { GuildMember, Message } from 'discord.js';
import { Client, Command } from '../class';
import { LINUX_USERNAME_REGEX } from '../class/AccountUtil';
export default class CreateAccount extends Command {
constructor(client: Client) {
@ -32,7 +33,7 @@ export default class CreateAccount extends Command {
if (checkAccount) return this.error(message.channel, 'Account already exists with this username.');
if (!this.client.util.isValidEmail(args[1])) return this.error(message.channel, 'Invalid email address supplied.');
if (!/^[a-z][-a-z0-9]*$/.test(args[2])) return this.error(message.channel, 'Invalid username supplied.');
if (!LINUX_USERNAME_REGEX.test(args[2])) return this.error(message.channel, 'Invalid username supplied.');
const confirmation = await this.loading(message.channel, 'Creating account...');
const data = await this.client.util.accounts.createAccount({ userID: args[0], username: args[2], emailAddress: args[1] }, message.author.id);

View File

@ -37,9 +37,9 @@ export default class CWG_Data extends Command {
embed.addField('Account ID', domain.account.userID, true);
embed.addField('Domain', domain.domain, true);
embed.addField('Port', String(domain.port), true);
embed.addField('Certificate Issuer', cert.data.issuer.organization[0], true);
embed.addField('Certificate Subject', cert.data.issuer.commonName, true);
embed.addField('Certificate Expiration Date', moment(cert.data.notAfter).format('dddd, MMMM Do YYYY, h:mm:ss A'), true);
embed.addField('Certificate Issuer', cert.issuer.organization[0], true);
embed.addField('Certificate Subject', cert.issuer.commonName, true);
embed.addField('Certificate Expiration Date', moment(cert.notAfter).format('dddd, MMMM Do YYYY, h:mm:ss A'), true);
embed.setFooter(this.client.user.username, this.client.user.avatarURL());
embed.setTimestamp();
return embed;

View File

@ -28,6 +28,7 @@ export { default as systemd } from './systemd';
export { default as tier } from './tier';
export { default as unban } from './unban';
export { default as unlock } from './unlock';
export { default as usermod } from './usermod';
export { default as users } from './users';
export { default as warn } from './warn';
export { default as whois } from './whois';

View File

@ -12,7 +12,7 @@ export default class Lock extends Command {
this.usage = `${this.client.config.prefix}lock [User Name | User ID/Mention] <Time> [Reason]`;
}
public async run(message: Message, args: string[]) { // eslint-disable-line
public async run(message: Message, args: string[]) {
try {
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0].replace(/[<@!>]/gi, '') }] });

75
src/commands/usermod.ts Normal file
View File

@ -0,0 +1,75 @@
import { Message } from 'discord.js';
import { Client, Command } from '../class';
import { LINUX_USERNAME_REGEX } from '../class/AccountUtil';
export default class Usermod extends Command {
constructor(client: Client) {
super(client);
this.name = 'usermod';
this.description = 'Modifies properties of a user\'s cloud account';
this.permissions = { roles: ['662163685439045632', '701454780828221450'] };
this.enabled = true;
}
public async run(message: Message, args: string[]) {
if (!args.length) return this.client.commands.get('help').run(message, [this.name]);
const [, property, value] = args;
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }] });
if (!account) return this.error(message.channel, 'Cannot find user.');
switch (property) {
case 'email': {
if (value === account.emailAddress) return this.error(message.channel, 'The new email address cannot be the same as the old one.');
if (await this.client.db.Account.exists({ emailAddress: value })) return this.error(message.channel, 'An account with this email address already exists.');
if (!this.client.util.isValidEmail(value)) return this.error(message.channel, 'The supplied email address is invalid.');
const modifyingPropertyResponse = await this.loading(message.channel, `Modifying \`${property}\` of \`${account.username}\`'s account...`);
await this.client.commands.get('notify')
.run(message, [account.username, ...(`Your email address has been changed from ${account.emailAddress} to ${value}.`.split(' '))]);
await account.updateOne({ emailAddress: value });
modifyingPropertyResponse.delete();
this.success(message.channel, `Successfully updated \`${account.username}\`'s email address.`);
break;
}
case 'username': {
if (value === account.username) return this.error(message.channel, 'The username cannot be the same as the old one.');
if (await this.client.db.Account.exists({ username: value })) return this.error(message.channel, 'An account with this username already exists.');
if (!LINUX_USERNAME_REGEX.test(value)) return this.error(message.channel, 'Please supply a valid username.');
if (value === 'root') return this.error(message.channel, 'This username is unavailable.');
const modifyingPropertyResponse = await this.loading(message.channel, `Modifying \`${property}\` of \`${account.username}\`'s account...`);
try {
await this.client.commands.get('lock')
.run(message, [account.username, ...(`Changing your username from \`${account.username}\` to \`${value}\`. DN/C`.split(' '))]);
await this.client.util.exec(`usermod -l ${value} ${account.username}`);
await this.client.util.exec(`usermod -d /home/${value} ${account.username}`);
await account.updateOne({
username: value,
homepath: `/home/${value}`,
});
await this.client.commands.get('unlock')
.run(message, [value, ...(`Your username has been successfully changed. Remember to use \`ssh ${value}@cloud.libraryofcode.org\` when logging in.`)]);
} catch (error) {
await this.client.commands.get('unlock')
.run(message, [account.username, ...('Your username change was unsuccessful. Please contact a Technician for more details.')]);
this.error(message.channel, 'Failed to modify username.');
return this.client.util.handleError(error);
}
modifyingPropertyResponse.delete();
this.success(message.channel, 'Successfully modified username.');
break;
}
default:
this.error(message.channel, 'Please specify a valid option.');
break;
}
}
}