diff --git a/src/class/Client.ts b/src/class/Client.ts index db791ad..312d4a1 100644 --- a/src/class/Client.ts +++ b/src/class/Client.ts @@ -11,7 +11,7 @@ import { Command, Util, Collection, Server, Event } from '.'; export default class Client extends Eris.Client { - public config: { 'token': string; 'cloudflare': string; 'prefix': string; 'emailPass': string; 'mongoURL': string; 'port': number; 'keyPair': { 'publicKey': string; 'privateKey': string; }; }; + public config: { 'token': string; 'cloudflare': string; 'prefix': string; 'emailPass': string; 'mongoURL': string; 'port': number; 'keyPair': { 'publicKey': string; 'privateKey': string; }; vendorKey: string; internalKey: string; }; public util: Util; diff --git a/src/class/Report.ts b/src/class/Report.ts new file mode 100644 index 0000000..8497ec0 --- /dev/null +++ b/src/class/Report.ts @@ -0,0 +1,126 @@ +import type { AxiosError } from 'axios'; +import axios from 'axios'; + +export interface SoftReport { + status: 'SUCCESS' | 'UNAUTHORIZED' | 'PERMISSION_DENIED' | 'CLIENT_ERROR' | 'SERVER_ERROR'; + userID?: string; + totalScore?: number; +} + +export interface HardReport extends SoftReport { + activityScore?: number; + roleScore?: number; + moderationScore?: number; + cloudServicesScore?: number; + miscScore?: number; + otherScore?: number; + inquiries?: [ { name: string; date: Date }? ]; +} + +export default class Report { + public static async getPIN(userID: string, auth: string): Promise<{ status: 'SUCCESS' | 'UNAUTHORIZED' | 'PERMISSION_DENIED' | 'CLIENT_ERROR' | 'SERVER_ERROR'; pin?: number[] }> { + try { + const { data } = await axios({ + method: 'get', + url: `https://loc.sh/int/pin?id=${userID}&auth=${auth}`, + }); + + return { + status: 'SUCCESS', + pin: data.message.pin, + }; + } catch (err) { + const error = err; + if (error.response?.status === 400) return { status: 'CLIENT_ERROR' }; + if (error.response?.status === 401) return { status: 'UNAUTHORIZED' }; + if (error.response?.status === 403) return { status: 'PERMISSION_DENIED' }; + if ((typeof error.response?.status === 'number') && error.response?.status >= 500) return { status: 'SERVER_ERROR' }; + throw new Error(err); + } + } + + /** + * Requests a Soft Inquiry from Library of Code sp-us Community Relations. + * @author Matthew R + * @param userID The user's ID, they must be in the server. Reports usually aren't generated for new users until the next recalculation. + * @param pin The last 4 digits of the member's PIN number. + * ```ts + * Report.soft('253600545972027394', 1102); + * ``` + */ + public static async soft(userID: string, pin: number, auth: string): Promise { + try { + if (pin < 4) throw new RangeError('PIN cannot be less than 4.'); + const { data } = await axios({ + method: 'post', + url: 'https://comm.libraryofcode.org/report/soft', + headers: { Authorization: auth }, + data: { + userID, + pin, + }, + }); + + return { + status: 'SUCCESS', + userID: data.message.userID, + totalScore: data.message.totalScore, + }; + } catch (err) { + const error = err; + if (error.response?.status === 400) return { status: 'CLIENT_ERROR' }; + if (error.response?.status === 401) return { status: 'UNAUTHORIZED' }; + if (error.response?.status === 403) return { status: 'PERMISSION_DENIED' }; + if ((typeof error.response?.status === 'number') && error.response?.status >= 500) return { status: 'SERVER_ERROR' }; + throw new Error(err); + } + } + + /** + * Requests a Hard Inquiry from Library of Code sp-us Community Relations. + * - Members who elected to be notified for hard pulls will receive a notification if your request is successful. + * - If the member's Community Report is locked, `HardReport.status` will equal `PERMISSION_DENIED`. + * @author Matthew R + * @param userID The user's ID, they must be in the server. Reports usually aren't generated for new users until the next recalculation. + * @param pin The last 4 digits of the member's PIN number. + * @param reason A reason for the hard inquiry. + * ```ts + * Report.hard('253600545972027394', 1102, 'Verification and Elibility for Personal Account'); + * ``` + */ + public static async hard(userID: string, pin: number, reason: string, auth: string): Promise { + try { + if (pin < 4) throw new RangeError('PIN cannot be less than 4.'); + const { data } = await axios({ + method: 'post', + url: 'https://comm.libraryofcode.org/report/hard', + headers: { Authorization: auth }, + data: { + userID, + pin, + reason, + }, + }); + + return { + status: 'SUCCESS', + userID: data.message.userID, + totalScore: data.message.totalScore, + activityScore: data.message.activityScore, + roleScore: data.message.rolesScore, + moderationScore: data.message.moderationScore, + cloudServicesScore: data.message.cloudServicesScore, + miscScore: data.message.miscScore, + otherScore: data.message.otherScore, + inquiries: data.message.inquiries, + }; + } catch (err) { + const error = err; + if (error.response?.status === 400) return { status: 'CLIENT_ERROR' }; + if (error.response?.status === 401) return { status: 'UNAUTHORIZED' }; + if (error.response?.status === 403) return { status: 'PERMISSION_DENIED' }; + if ((typeof error.response?.status === 'number') && error.response?.status >= 500) return { status: 'SERVER_ERROR' }; + throw new Error(err); + } + } +} diff --git a/src/class/index.ts b/src/class/index.ts index ea03741..fa2579b 100644 --- a/src/class/index.ts +++ b/src/class/index.ts @@ -4,6 +4,7 @@ export { default as Collection } from './Collection'; export { default as Command } from './Command'; export { default as Event } from './Event'; export { default as LocalStorage } from './LocalStorage'; +export { default as Report } from './Report'; export { default as RichEmbed } from './RichEmbed'; export { default as Route } from './Route'; export { default as Security } from './Security'; diff --git a/src/cscli/main.ts b/src/cscli/main.ts index 84655f2..8b7b8ab 100644 --- a/src/cscli/main.ts +++ b/src/cscli/main.ts @@ -3,7 +3,7 @@ import net from 'net'; import crypto from 'crypto'; import { promises as fs } from 'fs'; -import { Client } from '../class'; +import { Client, Report } from '../class'; import { dataConversion } from '../functions'; export default class CSCLI { @@ -39,6 +39,21 @@ export default class CSCLI { const parsed: { Username: string, Type: string, Message?: string, HMAC: string } = JSON.parse(args[0]); // FINISH VERIFICATION CHECKS switch (parsed.Type) { + case 'score': + const acc = await this.client.db.Account.findOne({ username: parsed.Username }); + if (!acc) { socket.destroy(); break; } + const pin = await Report.getPIN(acc.userID, this.client.config.internalKey); + if (pin.status !== 'SUCCESS') { socket.destroy(); break; } + + const report = await Report.soft(acc.userID, pin.pin[2], this.client.config.vendorKey); + if (report.status !== 'SUCCESS') { socket.destroy(); break; } + + if (!report.totalScore) { socket.write('N/C\n'); socket.destroy(); break; } + if (report.totalScore === 0) { socket.write('---\n'); socket.destroy(); break; } + + socket.write(`${report.totalScore}\n`); + socket.destroy(); + break; case 'lock': await this.client.util.accounts.lock(parsed.Username, this.client.user.id, { reason: parsed.Message }); break;