Merge branch 'master' of gitlab.libraryofcode.org:engineering/cloudservices
commit
9400caaea9
|
@ -145,7 +145,7 @@ export default class Util {
|
||||||
await this.exec(`chage -d0 ${username}`);
|
await this.exec(`chage -d0 ${username}`);
|
||||||
|
|
||||||
const account = new this.client.db.Account({
|
const account = new this.client.db.Account({
|
||||||
username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, ssInit: false,
|
username, userID, emailAddress, createdBy: moderatorID, createdAt: new Date(), locked: false, ssInit: false, homepath: `/home/${username}`,
|
||||||
});
|
});
|
||||||
return account.save();
|
return account.save();
|
||||||
}
|
}
|
||||||
|
@ -155,10 +155,10 @@ export default class Util {
|
||||||
if (!account) throw new Error('Account not found');
|
if (!account) throw new Error('Account not found');
|
||||||
this.exec(`lock ${username}`);
|
this.exec(`lock ${username}`);
|
||||||
const tasks = [
|
const tasks = [
|
||||||
this.exec(`deluser ${username} --remove-home --backup-to /management/Archives && rm -rf -R /home/${username}`),
|
this.exec(`deluser ${username} --remove-home --backup-to /management/Archives && rm -rf -R ${account.homepath} && groupdel ${account.homepath.replace('/home/', '')}`),
|
||||||
this.client.removeGuildMemberRole('446067825673633794', account.userID, '546457886440685578', 'Cloud Account Deleted'),
|
|
||||||
this.client.db.Account.deleteOne({ username }),
|
this.client.db.Account.deleteOne({ username }),
|
||||||
];
|
];
|
||||||
|
this.client.removeGuildMemberRole('446067825673633794', account.userID, '546457886440685578', 'Cloud Account Deleted').catch();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
await Promise.all(tasks);
|
await Promise.all(tasks);
|
||||||
}
|
}
|
||||||
|
@ -166,11 +166,11 @@ export default class Util {
|
||||||
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise<Message> {
|
public async messageCollector(message: Message, question: string, timeout: number, shouldDelete = false, choices: string[] = null, filter = (msg: Message): boolean|void => {}): Promise<Message> {
|
||||||
const msg = await message.channel.createMessage(question);
|
const msg = await message.channel.createMessage(question);
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
setTimeout(() => { if (shouldDelete) msg.delete(); rej(new Error('Did not supply a valid input in time')); }, timeout);
|
setTimeout(() => { if (shouldDelete) msg.delete().catch(); rej(new Error('Did not supply a valid input in time')); }, timeout);
|
||||||
this.client.on('messageCreate', (Msg) => {
|
this.client.on('messageCreate', (Msg) => {
|
||||||
if (filter(Msg) === false) return;
|
if (filter(Msg) === false) return;
|
||||||
const verif = choices ? choices.includes(Msg.content) : Msg.content;
|
const verif = choices ? choices.includes(Msg.content) : Msg.content;
|
||||||
if (verif) { if (shouldDelete) msg.delete(); res(Msg); }
|
if (verif) { if (shouldDelete) msg.delete().catch(); res(Msg); }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -238,9 +238,9 @@ export default class Util {
|
||||||
return Promise.resolve(log);
|
return Promise.resolve(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAcctHash(username: string) {
|
public getAcctHash(userpath: string) {
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(`/home/${username}/.securesign/auth`).toString();
|
return fs.readFileSync(`${userpath}/.securesign/auth`).toString();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ export default class DeleteAccount extends Command {
|
||||||
super(client);
|
super(client);
|
||||||
this.name = 'deleteaccount';
|
this.name = 'deleteaccount';
|
||||||
this.description = 'Delete an account on the Cloud VM';
|
this.description = 'Delete an account on the Cloud VM';
|
||||||
this.usage = `${this.client.config.prefix}deleteaccount [User Name | User ID | Email Address] [Reason] | ${this.client.config.prefix}deleteaccount [Username] [Reason] | ${this.client.config.prefix}deleteaccount [Email] [Reason]`;
|
this.usage = `${this.client.config.prefix}deleteaccount [User Name | User ID | Email Address] [Reason]`;
|
||||||
this.aliases = ['deleteacc', 'dacc', 'daccount', 'delete'];
|
this.aliases = ['deleteacc', 'dacc', 'daccount', 'delete'];
|
||||||
this.permissions = { roles: ['475817826251440128', '525441307037007902'] };
|
this.permissions = { roles: ['475817826251440128', '525441307037007902'] };
|
||||||
this.guildOnly = true;
|
this.guildOnly = true;
|
||||||
|
@ -20,7 +20,7 @@ export default class DeleteAccount extends Command {
|
||||||
if (!args[1]) return this.client.commands.get('help').run(message, [this.name]);
|
if (!args[1]) 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] }, { emailAddress: args[0] }] });
|
const account = await this.client.db.Account.findOne({ $or: [{ username: args[0] }, { userID: args[0] }, { emailAddress: args[0] }] });
|
||||||
if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`);
|
if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found.***`);
|
||||||
const { root, username, userID, emailAddress } = account;
|
const { root, username, userID, emailAddress, homepath } = account;
|
||||||
if (root) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied.***`);
|
if (root) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied.***`);
|
||||||
|
|
||||||
const pad = (number: number, amount: number): string => '0'.repeat(amount - number.toString().length) + number;
|
const pad = (number: number, amount: number): string => '0'.repeat(amount - number.toString().length) + number;
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default class Disk extends Command {
|
||||||
if (account.root || args[0].includes('./')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`);
|
if (account.root || args[0].includes('./')) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`);
|
||||||
const diskReply = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching total disk size may up to 10 minutes. This message will edit when the disk size has been located.***`);
|
const diskReply = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Fetching total disk size may up to 10 minutes. This message will edit when the disk size has been located.***`);
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
const result = await this.client.util.exec(`du -s /home/${account.username}`);
|
const result = await this.client.util.exec(`du -s ${account.homepath}`);
|
||||||
const end = Date.now();
|
const end = Date.now();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const totalTime: string = moment.preciseDiff(start, end);
|
const totalTime: string = moment.preciseDiff(start, end);
|
||||||
|
|
|
@ -15,6 +15,7 @@ export { default as parse } from './parse';
|
||||||
export { default as parseall } from './parseall';
|
export { default as parseall } from './parseall';
|
||||||
export { default as ping } from './ping';
|
export { default as ping } from './ping';
|
||||||
export { default as pull } from './pull';
|
export { default as pull } from './pull';
|
||||||
|
export { default as resetpassword } from './resetpassword';
|
||||||
export { default as restart } from './restart';
|
export { default as restart } from './restart';
|
||||||
export { default as securesign } from './securesign';
|
export { default as securesign } from './securesign';
|
||||||
export { default as sysinfo } from './sysinfo';
|
export { default as sysinfo } from './sysinfo';
|
||||||
|
|
|
@ -29,6 +29,8 @@ export default class Load extends Command {
|
||||||
delete require.cache[`${corepath}/class/Util.js`];
|
delete require.cache[`${corepath}/class/Util.js`];
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
delete require.cache[`${corepath}/commands/index.js`];
|
||||||
|
delete require.cache[`${corepath}/commands/${args[1]}.js`];
|
||||||
const cmdIndex = require('../commands');
|
const cmdIndex = require('../commands');
|
||||||
let Cmd = cmdIndex[args[1]];
|
let Cmd = cmdIndex[args[1]];
|
||||||
if (!Cmd) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`);
|
if (!Cmd) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Could not find file***`);
|
||||||
|
|
|
@ -20,12 +20,12 @@ export default class Parse extends Command {
|
||||||
if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`);
|
if (!account) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot find user.***`);
|
||||||
let dir: string[];
|
let dir: string[];
|
||||||
try {
|
try {
|
||||||
dir = await fs.readdir(`/home/${account.username}/Validation`);
|
dir = await fs.readdir(`${account.homepath}/Validation`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`);
|
return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate Validation directory.***`);
|
||||||
}
|
}
|
||||||
if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`);
|
if (!dir.length) return message.channel.createMessage(`***${this.client.stores.emojis.error} Cannot locate certificate.***`);
|
||||||
const cert = parseCert(`/home/${account.username}/Validation/${dir[0]}`);
|
const cert = parseCert(`${account.homepath}/Validation/${dir[0]}`);
|
||||||
const subjectCommonName = cert.subject.commonName ? cert.subject.commonName : 'Not Specified';
|
const subjectCommonName = cert.subject.commonName ? cert.subject.commonName : 'Not Specified';
|
||||||
const subjectEmailAddress = cert.subject.emailAddress ? cert.subject.emailAddress : 'Not Specified';
|
const subjectEmailAddress = cert.subject.emailAddress ? cert.subject.emailAddress : 'Not Specified';
|
||||||
const subjectOrganization = cert.subject.organizationName ? cert.subject.organizationName : 'Not Specified';
|
const subjectOrganization = cert.subject.organizationName ? cert.subject.organizationName : 'Not Specified';
|
||||||
|
@ -39,7 +39,7 @@ export default class Parse extends Command {
|
||||||
const user = this.client.users.get(account.userID) ? this.client.users.get(account.userID) : await this.client.getRESTUser(account.userID);
|
const user = this.client.users.get(account.userID) ? this.client.users.get(account.userID) : await this.client.getRESTUser(account.userID);
|
||||||
const embed = new RichEmbed();
|
const embed = new RichEmbed();
|
||||||
embed.setTitle('Parse x509 Certificate');
|
embed.setTitle('Parse x509 Certificate');
|
||||||
embed.setDescription(`/home/${account.username}/Validation/${dir[0]} | ${account.username} <@${user.id}>`);
|
embed.setDescription(`${account.homepath}/Validation/${dir[0]} | ${account.username} <@${user.id}>`);
|
||||||
embed.setColor(3447003);
|
embed.setColor(3447003);
|
||||||
embed.addField('Subject', `**Common Name:** ${subjectCommonName}\n**Email Address:** ${subjectEmailAddress}\n**Organization:** ${subjectOrganization}\n**Organizational Unit:** ${subjectOrganizationalUnit}\n**Country:** ${subjectCountry}`, true);
|
embed.addField('Subject', `**Common Name:** ${subjectCommonName}\n**Email Address:** ${subjectEmailAddress}\n**Organization:** ${subjectOrganization}\n**Organizational Unit:** ${subjectOrganizationalUnit}\n**Country:** ${subjectCountry}`, true);
|
||||||
embed.addField('Issuer', `**Common Name:** ${issuerCommonName}\n**Email Address:** ${issuerEmailAddress}\n**Organization:** ${issuerOrganization}\n**Organizational Unit:** ${issuerOrganizationalUnit}\n**Country:** ${issuerCountry}`, true);
|
embed.addField('Issuer', `**Common Name:** ${issuerCommonName}\n**Email Address:** ${issuerEmailAddress}\n**Organization:** ${issuerOrganization}\n**Organizational Unit:** ${issuerOrganizationalUnit}\n**Country:** ${issuerCountry}`, true);
|
||||||
|
|
|
@ -24,13 +24,13 @@ export default class Parseall extends Command {
|
||||||
embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL);
|
embed.setFooter(`Requested by ${message.member.username}#${message.member.discriminator}`, message.member.avatarURL);
|
||||||
embed.setTimestamp();
|
embed.setTimestamp();
|
||||||
const search = await this.client.db.Account.find();
|
const search = await this.client.db.Account.find();
|
||||||
const accounts = search.map((acc) => acc.username);
|
const accounts = search.map((acc) => acc.homepath);
|
||||||
const final: string[] = [];
|
const final: string[] = [];
|
||||||
|
|
||||||
accounts.forEach(async (a) => {
|
accounts.forEach(async (a) => {
|
||||||
try {
|
try {
|
||||||
const certFile = readdirSync(`/home/${a}/Validation`)[0];
|
const certFile = readdirSync(`${a}/Validation`)[0];
|
||||||
const { notAfter } = parseCert(`/home/${a}/Validation/${certFile}`);
|
const { notAfter } = parseCert(`${a}/Validation/${certFile}`);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const time = moment.preciseDiff(new Date(), notAfter);
|
const time = moment.preciseDiff(new Date(), notAfter);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { Message } from 'eris';
|
||||||
|
import { Client } from '..';
|
||||||
|
import { Command } from '../class';
|
||||||
|
|
||||||
|
export default class ResetPassword extends Command {
|
||||||
|
constructor(client: Client) {
|
||||||
|
super(client);
|
||||||
|
|
||||||
|
this.name = 'resetpassword';
|
||||||
|
this.description = 'Reset a cloud account password';
|
||||||
|
this.aliases = ['resetpasswd', 'resetpw'];
|
||||||
|
this.usage = `${this.client.config.prefix}resetpassword [Username | User ID | Email]`;
|
||||||
|
this.permissions = { roles: ['525441307037007902', '475817826251440128'] };
|
||||||
|
this.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async run(message: Message, args: string[]) {
|
||||||
|
try {
|
||||||
|
if (!args[0]) 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] }, { emailAddress: args[0] }] });
|
||||||
|
if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`);
|
||||||
|
if (account.root) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Permission denied***`);
|
||||||
|
|
||||||
|
const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Resetting password for ${account.username}...***`);
|
||||||
|
const tempPass = this.client.util.randomPassword();
|
||||||
|
await this.client.util.exec(`echo '${account.username}:${tempPass}' | chpasswd`);
|
||||||
|
|
||||||
|
let completeMessage = `${this.client.stores.emojis.success} ***Password for ${account.username} reset to \`${tempPass}\`***`;
|
||||||
|
const dmChannel = await this.client.getDMChannel(account.userID);
|
||||||
|
try {
|
||||||
|
await dmChannel.createMessage(`We received a password reset request from you, your new password is \`${tempPass}\`.\n`
|
||||||
|
+ `You will be asked to change your password when you log back in, \`(current) UNIX password\` is \`${tempPass}\`, then create a password that is at least 12 characters long, with at least one number, special character, and an uppercase letter.\n`
|
||||||
|
+ 'Bear in mind that when you enter your password, it will be blank, so be careful not to type in your password incorrectly.');
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 50007) completeMessage += '\n*Unable to DM user*';
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return msg.edit(completeMessage);
|
||||||
|
} catch (error) {
|
||||||
|
return this.client.util.handleError(error, message, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ export default class SecureSign_ActivateKey extends Command {
|
||||||
if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`);
|
if (!account) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not found***`);
|
||||||
if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`);
|
if (!account.hash) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Account not initialized***`);
|
||||||
const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Activating key...***`);
|
const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Activating key...***`);
|
||||||
const hash = this.client.util.getAcctHash(account.username);
|
const hash = this.client.util.getAcctHash(account.homepath);
|
||||||
try {
|
try {
|
||||||
await axios({
|
await axios({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default class SecureSign_Init extends Command {
|
||||||
if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``);
|
if (options.m && (!Number(options.m) || (options.m !== '256' && options.m !== '384' && options.m !== '512'))) return message.channel.createMessage(`${this.client.stores.emojis.error} ***Invalid SHA Digest selected, choose between \`256\`, \`384\` or \`512\``);
|
||||||
|
|
||||||
const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`);
|
const msg = await message.channel.createMessage(`${this.client.stores.emojis.loading} ***Creating certificate...***`);
|
||||||
const hash = this.client.util.getAcctHash(account.username);
|
const hash = this.client.util.getAcctHash(account.homepath);
|
||||||
|
|
||||||
// Check if they can generate certificate
|
// Check if they can generate certificate
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { inspect } from 'util';
|
||||||
import { Client } from '..';
|
import { Client } from '..';
|
||||||
|
|
||||||
export default function checkSS(client: Client) {
|
export default function checkSS(client: Client) {
|
||||||
|
@ -7,9 +8,10 @@ export default function checkSS(client: Client) {
|
||||||
try {
|
try {
|
||||||
const accounts = await client.db.Account.find();
|
const accounts = await client.db.Account.find();
|
||||||
const hashes = accounts.filter((h) => h.hash);
|
const hashes = accounts.filter((h) => h.hash);
|
||||||
for (const { userID, username } of hashes) {
|
for (const { userID, homepath } of hashes) {
|
||||||
try {
|
try {
|
||||||
const hash = client.util.getAcctHash(username);
|
const hash = client.util.getAcctHash(homepath);
|
||||||
|
if (hash === null) throw new Error('Unable to locate auth file, homepath is probably incorrect');
|
||||||
await axios({
|
await axios({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: 'https://api.securesign.org/account/details',
|
url: 'https://api.securesign.org/account/details',
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Document, Schema, model } from 'mongoose';
|
||||||
export interface AccountInterface extends Document {
|
export interface AccountInterface extends Document {
|
||||||
username: string,
|
username: string,
|
||||||
userID: string,
|
userID: string,
|
||||||
|
homepath: string
|
||||||
emailAddress: string,
|
emailAddress: string,
|
||||||
createdBy: string,
|
createdBy: string,
|
||||||
createdAt: Date,
|
createdAt: Date,
|
||||||
|
@ -23,6 +24,7 @@ export interface AccountInterface extends Document {
|
||||||
const Account: Schema = new Schema({
|
const Account: Schema = new Schema({
|
||||||
username: String,
|
username: String,
|
||||||
userID: String,
|
userID: String,
|
||||||
|
homepath: String,
|
||||||
emailAddress: String,
|
emailAddress: String,
|
||||||
createdBy: String,
|
createdBy: String,
|
||||||
createdAt: Date,
|
createdAt: Date,
|
||||||
|
|
Loading…
Reference in New Issue