src/users/users.service.ts
Properties |
|
Methods |
|
constructor(databaseService: DatabaseService, utilService: UtilsService, configService: ConfigService, codesService: CodesService, emailService: EmailsService, cloudflareService: CloudflareService, bezosService: BezosService, csamService: CsamService, uploadService: UploadsService)
|
||||||||||||||||||||||||||||||
|
Defined in src/users/users.service.ts:22
|
||||||||||||||||||||||||||||||
|
Parameters :
|
| Public Async blockUser |
blockUser(user: string, until: number, reason: string, perma: boolean)
|
|
Defined in src/users/users.service.ts:566
|
|
Returns :
any
|
| Public Async changeUserEmail |
changeUserEmail(user: string, email: string)
|
|
Defined in src/users/users.service.ts:612
|
|
Returns :
any
|
| Public Async confirmUserEmail |
confirmUserEmail(snowflake: string, code: string)
|
|
Defined in src/users/users.service.ts:259
|
|
Returns :
any
|
| Public Async create | ||||||||||||||||||||||||
create(username: string, password: string, email: string, customSnw?: string, sendEmail)
|
||||||||||||||||||||||||
|
Defined in src/users/users.service.ts:36
|
||||||||||||||||||||||||
|
Parameters :
Returns :
Promise<string>
|
| Public Async createUserApikey |
createUserApikey(user: string, ip: string)
|
|
Defined in src/users/users.service.ts:281
|
|
Returns :
any
|
| Public Async deleteUserAccount | ||||||
deleteUserAccount(user: string)
|
||||||
|
Defined in src/users/users.service.ts:696
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async deleteUserApiKey | ||||||
deleteUserApiKey(snowflake: string)
|
||||||
|
Defined in src/users/users.service.ts:275
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getActiveBlocks |
getActiveBlocks()
|
|
Defined in src/users/users.service.ts:494
|
|
Returns :
unknown
|
| Public Async getCoreUserData | ||||||
getCoreUserData(snowflake: string)
|
||||||
|
Defined in src/users/users.service.ts:312
|
||||||
|
Parameters :
Returns :
Promise<FileglassMainDashBoard>
|
| Public Async getDevEmails |
getDevEmails()
|
|
Defined in src/users/users.service.ts:295
|
|
Returns :
Promise<string[]>
|
| Public Async getLeaderBoard | ||||||||
getLeaderBoard(total: number)
|
||||||||
|
Defined in src/users/users.service.ts:380
|
||||||||
|
Parameters :
Returns :
Promise<literal type[]>
|
| Public Async getPassword | ||||||
getPassword(snowflake: string)
|
||||||
|
Defined in src/users/users.service.ts:139
|
||||||
|
Parameters :
Returns :
Promise<string>
|
| Public Async getUploadMinimalDataFromApikey |
getUploadMinimalDataFromApikey(apikey: string, ip: string)
|
|
Defined in src/users/users.service.ts:179
|
|
Returns :
unknown
|
| Public Async getUploadMinimalDataFromUser | ||||||
getUploadMinimalDataFromUser(user: string)
|
||||||
|
Defined in src/users/users.service.ts:150
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getUser | |||||||||
getUser(data: string, dataType: "username" | "email_hash")
|
|||||||||
|
Defined in src/users/users.service.ts:120
|
|||||||||
|
Parameters :
Returns :
Promise<literal type | undefined>
|
| Public Async getUserApiKey | ||||||
getUserApiKey(snowflake: string)
|
||||||
|
Defined in src/users/users.service.ts:270
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getUserBlockData | ||||||
getUserBlockData(user: string)
|
||||||
|
Defined in src/users/users.service.ts:524
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getUserCname | ||||||
getUserCname(user: string)
|
||||||
|
Defined in src/users/users.service.ts:443
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getUserDomain | ||||||
getUserDomain(user: string)
|
||||||
|
Defined in src/users/users.service.ts:436
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getUserEmail | ||||||
getUserEmail(snowflake: string)
|
||||||
|
Defined in src/users/users.service.ts:250
|
||||||
|
Parameters :
Returns :
Promise<string>
|
| Public Async getUsername | ||||||
getUsername(snowflake: string)
|
||||||
|
Defined in src/users/users.service.ts:304
|
||||||
|
Parameters :
Returns :
Promise<string>
|
| Public Async getUserPasswordHash | ||||||
getUserPasswordHash(user: string)
|
||||||
|
Defined in src/users/users.service.ts:423
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async getUserPfp | ||||||
getUserPfp(user: string)
|
||||||
|
Defined in src/users/users.service.ts:633
|
||||||
|
Parameters :
Returns :
unknown
|
| Private Async isCnameSavedWithDomain |
isCnameSavedWithDomain(cname: string, domain: string)
|
|
Defined in src/users/users.service.ts:452
|
|
Returns :
unknown
|
| Public Async isIpRegistered | ||||||
isIpRegistered(ip: string)
|
||||||
|
Defined in src/users/users.service.ts:92
|
||||||
|
Parameters :
Returns :
unknown
|
| Public Async isSnowflakeValid | |||||||||
isSnowflakeValid(snowflake: string, excessData?: T)
|
|||||||||
|
Defined in src/users/users.service.ts:222
|
|||||||||
Type parameters :
|
|||||||||
|
Parameters :
Returns :
Promise<literal type>
|
| Public Async sendEmailConfirmation |
sendEmailConfirmation(email: string, snowflake: string, username: string)
|
|
Defined in src/users/users.service.ts:72
|
|
Returns :
any
|
| Public Async sendEmailToUser |
sendEmailToUser(user: string, emailBody: string, subject: string)
|
|
Defined in src/users/users.service.ts:513
|
|
Sends an email to the user (body has to be HTML)
Returns :
any
|
| Public Async setFieldData | ||||||||||||
setFieldData(user: string, field: T, state)
|
||||||||||||
|
Defined in src/users/users.service.ts:408
|
||||||||||||
Type parameters :
|
||||||||||||
|
Parameters :
Returns :
any
|
| Public Async setUserCname |
setUserCname(user: string, cname: string, domain?: string)
|
|
Defined in src/users/users.service.ts:461
|
|
Returns :
any
|
| Public Async setUserDomain |
setUserDomain(user: string, domain: string, cname?: string)
|
|
Defined in src/users/users.service.ts:487
|
|
Returns :
any
|
| Public Async setUserPfp | |||||||||
setUserPfp(type: Type, args: PfpSetterArgs<Type>)
|
|||||||||
|
Defined in src/users/users.service.ts:661
|
|||||||||
Type parameters :
|
|||||||||
|
Parameters :
Returns :
unknown
|
| Public Async unblockUser | ||||||
unblockUser(user: string)
|
||||||
|
Defined in src/users/users.service.ts:538
|
||||||
|
Parameters :
Returns :
any
|
| Public Async userExists |
userExists(email_hash: string, username: string)
|
|
Defined in src/users/users.service.ts:100
|
|
Returns :
Promise<boolean>
|
| Private Async writePfpNameToDb |
writePfpNameToDb(user: string, name: string, type)
|
|
Defined in src/users/users.service.ts:646
|
|
Returns :
any
|
| Private Readonly logger |
Default value : new Logger(UsersService.name)
|
|
Defined in src/users/users.service.ts:22
|
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
import { DatabaseService } from '../database/database.service';
import { UtilsService } from '../utils/utils.service';
import * as Enums from '../utils/enums/responses.enum';
import { FileglassMainDashBoard } from '../../types';
import Prisma, { PFP_TYPE } from '@prisma/client';
import { AlreadyRegisteredException } from '../exceptions/already-registered.exception';
import { ConfigService } from '@nestjs/config';
import { ApikeyException } from '../exceptions/apikey.exception';
import { BlockedException } from '../exceptions/blocked.exception';
import { CodesService } from '../codes/codes.service';
import { EmailsService } from '../emails/emails.service';
import { CloudflareService } from '../cloud/cloudflare/cloudflare.service';
import { BezosService } from '../cloud/bezos.service';
import { CsamService } from '../cloud/csam/csam.service';
import { GenericException } from '../exceptions/generic.exception';
import { GenericRespEnum } from '../utils/enums/responses.enum';
import { UploadsService } from '../uploads/uploads.service';
@Injectable()
export class UsersService {
private readonly logger = new Logger(UsersService.name);
constructor(
private readonly databaseService: DatabaseService,
private readonly utilService: UtilsService,
private readonly configService: ConfigService,
private readonly codesService: CodesService,
private readonly emailService: EmailsService,
private readonly cloudflareService: CloudflareService,
private readonly bezosService: BezosService,
private readonly csamService: CsamService,
@Inject(forwardRef(() => UploadsService))
private readonly uploadService: UploadsService,
) {}
public async create(
username: string,
password: string,
email: string,
customSnw?: string,
sendEmail = true,
): Promise<string> {
const emailHash = this.utilService.sha(email);
if (await this.userExists(emailHash, username)) {
throw new AlreadyRegisteredException();
}
const snowflake = customSnw || (await this.utilService.generateSnowflake());
await this.databaseService.write.users.create({
data: {
snowflake,
username,
email_hash: emailHash,
email: this.utilService.encrypt(email),
password: await this.utilService.hashPass(password),
blocked: false, // idk jesus is lazy so imma need to do that
admin: false,
twostep: false,
date: Date.now().toString(),
init_ip: 'ip',
sus: false,
email_verified: !sendEmail,
},
});
if (sendEmail) {
await this.sendEmailConfirmation(email, snowflake, username);
}
return Enums.RegisterRespEnum.USER_REGISTERED;
}
public async sendEmailConfirmation(
email: string,
snowflake: string,
username: string,
) {
const code = await this.codesService.createCode(
'EMAIL_CONFIRM_INIT',
20,
snowflake,
);
const body = this.emailService.bodies.confirmEmail(
this.utilService.buildConfirmUrl(code.code),
username,
true,
);
await new this.emailService.Mailer(email, 'Confirm your email', true)
.append(body)
.deliver();
}
public async isIpRegistered(ip: string) {
return (
(await this.databaseService.read.users.count({
where: { init_ip: ip },
})) > 0
);
}
public async userExists(
email_hash: string,
username: string,
): Promise<boolean> {
const queryResult = await this.databaseService.read.users.count({
where: {
OR: [
{
email_hash,
},
{
username,
},
],
},
});
return queryResult > 0;
}
public async getUser(
data: string,
dataType: 'username' | 'email_hash',
): Promise<{ snowflake: string; emailVerified: boolean } | undefined> {
this.logger.debug(`Selecting ${dataType} with value: ${data}`);
const retval = await this.databaseService.read.users.findFirst({
where: {
[dataType]: data,
},
select: {
snowflake: true,
email_verified: true,
},
});
return retval
? { snowflake: retval.snowflake, emailVerified: retval.email_verified }
: undefined;
}
public async getPassword(snowflake: string): Promise<string> {
const r = await this.databaseService.read.users.findFirst({
where: {
snowflake,
},
select: {
password: true,
},
});
return r.password;
}
public async getUploadMinimalDataFromUser(user: string) {
const akey = await this.getUserApiKey(user);
const result = await this.databaseService.read.api_keys.findFirst({
where: {
hash: akey.hash,
},
select: {
owner: true,
ip: true,
users: {
select: {
blocked: true,
cname: true,
domain: true,
raw: true,
embed: true,
},
},
},
});
return {
snowflake: result.owner,
cname: result.users.cname!,
ip: result.ip!,
domain: result.users.domain,
raw: result.users.raw,
embed: result!.users.embed!,
};
}
public async getUploadMinimalDataFromApikey(apikey: string, ip: string) {
const result = await this.databaseService.read.api_keys.findFirst({
where: {
hash: this.utilService.sha(apikey),
},
select: {
owner: true,
ip: true,
users: {
select: {
blocked: true,
cname: true,
domain: true,
raw: true,
embed: true,
},
},
},
});
if (result) {
if (!result.users.blocked) {
if (result.ip === ip || result.ip === '*') {
return {
snowflake: result.owner,
cname: result.users.cname!,
ip: result.ip!,
domain: result.users.domain,
raw: result.users.raw,
embed: result!.users.embed!,
};
} else {
throw new BlockedException(true);
}
} else {
this.logger.log('Resulting as false');
throw new BlockedException();
}
} else {
this.logger.log('Throwing invalid apikey exception');
throw new ApikeyException(true);
}
}
public async isSnowflakeValid<T = Prisma.Prisma.usersSelect>(
snowflake: string,
excessData?: T,
): Promise<{
valid: boolean;
excessResult: Prisma.Prisma.CheckSelect<T, any, any>;
}> {
const data = await this.databaseService.read.users.findFirst({
where: {
snowflake,
},
select: {
snowflake: true,
...((excessData as Prisma.Prisma.usersSelect) || undefined),
},
});
return {
valid: data !== null,
excessResult: excessData
? (data as Prisma.Prisma.CheckSelect<T, any, any>) ||
(this.utilService.setAllPropsTo(
excessData as unknown as { [key: string]: unknown },
false,
) as Prisma.Prisma.CheckSelect<T, any, any>)
: undefined,
};
}
public async getUserEmail(snowflake: string): Promise<string> {
const r = await this.databaseService.read.users.findFirst({
where: { snowflake },
select: { email: true },
});
return this.utilService.decrypt(r.email);
}
public async confirmUserEmail(snowflake: string, code: string) {
this.logger.debug(`Confirming user email with code ${code}`);
await this.databaseService.write.users.update({
where: { snowflake },
data: {
email_verified: true,
codes: { update: { where: { code }, data: { used: true } } },
},
});
}
public async getUserApiKey(snowflake: string) {
return await this.databaseService.read.api_keys.findFirst({
where: { owner: snowflake },
});
}
public async deleteUserApiKey(snowflake: string) {
return await this.databaseService.write.api_keys.deleteMany({
where: { owner: snowflake },
});
}
public async createUserApikey(user: string, ip: string) {
const key = this.utilService.sha(
await this.utilService.generateSnowflake(50),
);
await this.deleteUserApiKey(user);
await this.databaseService.write.api_keys.create({
data: {
ip,
owner: user,
api_key: this.utilService.encrypt(key),
hash: this.utilService.sha(key),
},
});
}
public async getDevEmails(): Promise<string[]> {
return (
await this.databaseService.read.users.findMany({
where: { admin: true },
select: { email: true },
})
).map((data) => this.utilService.decrypt(data.email));
}
public async getUsername(snowflake: string): Promise<string> {
return (
await this.databaseService.read.users.findFirst({
where: { snowflake },
select: { username: true },
})
).username;
}
public async getCoreUserData(
snowflake: string,
): Promise<FileglassMainDashBoard> {
const r = await this.databaseService.read.users.findFirst({
where: { snowflake },
select: {
username: true,
tier: true,
email: true,
pfp: true,
email_verified: true,
leaderboard_private: true,
admin: true,
domain: true,
cname: true,
raw: true,
pfp_type: true,
twostep: true,
uploads_uploadsTousers: {
select: {
size: true,
date: true,
views: true,
likes: true,
path: true,
mime: true,
},
orderBy: { date: 'desc' },
},
},
});
let totalSize = 0;
let totalViews = 0;
const dates: string[] = [];
r.uploads_uploadsTousers.forEach((upload) => {
totalSize += parseInt(upload.size!);
totalViews += upload.views!;
dates.push(upload.date!);
});
let newestUpload;
try {
newestUpload = `${r.uploads_uploadsTousers[0].path}.${
r.uploads_uploadsTousers[0].mime!.split('/')[1]
}`;
} catch (err) {
newestUpload = '0i850.png';
}
return {
memUsage: totalSize,
totalPosts: r.uploads_uploadsTousers.length,
newestUpload,
totalViews,
dates,
username: r!.username!,
tier: r!.tier!,
email: this.utilService.decrypt(r!.email!),
pfp: r!.pfp!,
emailVerified: r!.email_verified!,
leaderboardPrivate: r!.leaderboard_private,
isAdmin: r!.admin || false,
domain: r!.domain,
cname: r!.cname === 'no-cname' ? 'c' : r!.cname!,
raw: r!.raw,
pfpDescriptor: r!.pfp_type,
twostep: r!.twostep,
};
}
public async getLeaderBoard(
// proudly pasted from the old src
total = 10,
): Promise<{ count: number; tier: number; username: string; pfp: string }[]> {
const r = await this.databaseService.read.users.findMany({
select: {
uploads: true,
username: true,
tier: true,
pfp: true,
},
orderBy: {
uploads: 'desc',
},
where: {
leaderboard_private: false,
},
take: total,
});
return r.map((user) => {
return {
count: user!.uploads!,
tier: user!.tier!,
username: user!.username!,
pfp: user.pfp!,
};
});
}
public async setFieldData<T extends keyof Prisma.Prisma.usersUpdateInput>(
user: string,
field: T,
state: Prisma.Prisma.usersUpdateInput[T],
) {
await this.databaseService.write.users.update({
where: {
snowflake: user,
},
data: {
[field]: state,
},
});
}
public async getUserPasswordHash(user: string) {
return (
await this.databaseService.read.users.findFirst({
where: {
snowflake: user,
},
select: {
password: true,
},
})
).password;
}
public async getUserDomain(user: string) {
const r = await this.databaseService.read.users.findFirst({
where: { snowflake: user },
select: { domain: true },
});
return r.domain;
}
public async getUserCname(user: string) {
const r = await this.databaseService.read.users.findFirst({
where: { snowflake: user },
select: { cname: true },
});
this.logger.debug(`User cname: ${r.cname}`);
return r.cname;
}
private async isCnameSavedWithDomain(cname: string, domain: string) {
const r = await this.databaseService.read.cnames.count({
where: {
domain,
cname,
},
});
return r > 0;
}
public async setUserCname(user: string, cname: string, domain?: string) {
domain = domain || (await this.getUserDomain(user));
const cnameId = await this.cloudflareService.createCname(cname, domain);
this.logger.debug('Cname', cname, 'cf response', cnameId);
if (!(await this.isCnameSavedWithDomain(cname, domain))) {
try {
await this.databaseService.write.cnames.create({
data: {
cname,
worker_bind: cnameId.workerId,
id: cnameId.dnsId,
creator: user,
},
});
} catch (err) {}
}
await this.databaseService.write.users.update({
where: { snowflake: user },
data: {
cname,
domain,
},
});
}
public async setUserDomain(user: string, domain: string, cname?: string) {
await this.setUserCname(
user,
cname || (await this.getUserCname(user)),
domain,
);
}
public async getActiveBlocks() {
return await this.databaseService.read.users.findMany({
where: {
blocked: true,
},
select: {
blocked_until: true,
snowflake: true,
ban_id: true,
},
});
}
/**
* Sends an email to the user (body has to be HTML)
* @param user
* @param emailBody
* @param subject
*/
public async sendEmailToUser(
user: string,
emailBody: string,
subject: string,
) {
const email = await this.getUserEmail(user);
const mailer = new this.emailService.Mailer(email, subject, true);
mailer.append(emailBody);
await mailer.deliver();
this.logger.log(`Email sent to: ${email} with subject: ${subject}`);
}
public async getUserBlockData(user: string) {
return await this.databaseService.read.users.findFirst({
where: {
snowflake: user,
},
select: {
blocked: true,
ban_id: true,
block_msg: true,
blocked_until: true,
username: true,
},
});
}
public async unblockUser(user: string) {
const blockData = await this.getUserBlockData(user);
const body = this.emailService.bodies.unblockMessage(
blockData.ban_id,
blockData.username,
);
await this.databaseService.write.users.update({
where: {
snowflake: user,
},
data: {
blocked: false,
bans: {
update: {
where: {
ban_id: blockData.ban_id,
},
data: {
ended: true,
},
},
},
},
});
await this.sendEmailToUser(user, body, 'Account Suspension');
this.logger.log(`User ${blockData.username} unblocked`);
}
public async blockUser(
user: string,
until: number,
reason: string,
perma: boolean,
) {
until = perma ? 95647388400000 : until; //until 5000-12-12
const banid = await this.utilService.generateSnowflake(15);
await this.databaseService.write.users.update({
where: {
snowflake: user,
},
data: {
blocked: true,
blocked_until: until.toString(),
ban_id: banid,
block_msg: reason,
bans: {
create: {
ban_id: banid,
ends: until.toString(),
ended: false,
reason,
},
},
},
});
const username = await this.getUsername(user);
await this.sendEmailToUser(
user,
this.emailService.bodies.blockMessage(
until,
perma,
reason,
banid,
username,
),
'Account Suspension',
);
this.logger.log(
`User ${username} blocked ${
perma ? 'permanently' : `for ${this.utilService.humanize(until)}`
}`,
);
}
public async changeUserEmail(user: string, email: string) {
const code = await this.codesService.createCode(
'EMAIL_CONFIRM_UPDATE',
20,
user,
email,
);
const username = await this.getUsername(user);
const body = this.emailService.bodies.confirmEmail(
this.utilService.buildConfirmUrl(code.code),
username,
false,
);
const mailer = new this.emailService.Mailer(
email,
'Confirm your email',
true,
);
await mailer.append(body).deliver();
}
public async getUserPfp(user: string) {
const r = await this.databaseService.read.users.findFirst({
where: {
snowflake: user,
},
select: {
pfp: true,
pfp_type: true,
},
});
return { url: r.pfp, type: r.pfp_type };
}
private async writePfpNameToDb(
user: string,
name: string,
type: keyof typeof PFP_TYPE,
) {
await this.databaseService.write.users.update({
where: {
snowflake: user,
},
data: {
pfp: name,
pfp_type: type,
},
});
}
public async setUserPfp<Type extends PFP_TYPE>(
type: Type,
args: PfpSetterArgs<Type>,
) {
const curr = await this.getUserPfp(args.user);
switch (type) {
case 'CUSTOM':
await this.bezosService.removeFromCdn(curr.url, 'pfps');
const isSafe = await this.csamService.isSafe(
args.file,
args.name,
args.mime,
);
if (!isSafe) {
throw new GenericException(GenericRespEnum.ERR_IMAGE_FILTERED, 403);
}
const fName = await this.utilService.generateSnowflake();
const ext = this.utilService.getImageExtension(args.name);
await this.bezosService.uploadToCdn(
args.file,
`${fName}.${ext}`,
args.mime,
'pfps',
);
await this.writePfpNameToDb(args.user, `${fName}.${ext}`, type);
return GenericRespEnum.PFP_UPDATED;
case 'DISCORD':
await this.writePfpNameToDb(args.user, args.name, type);
return GenericRespEnum.PFP_UPDATED;
case 'GITHUB':
await this.writePfpNameToDb(args.user, args.name, type);
return GenericRespEnum.PFP_UPDATED;
}
}
public async deleteUserAccount(user: string) {
const uname = await this.getUsername(user);
const emailaddr = await this.getUserEmail(user);
const akey = await this.getUserApiKey(user);
const emailBod = this.emailService.bodies.accountDelete(uname);
await new this.emailService.Mailer(
emailaddr,
'Account marked for deletion',
true,
)
.append(emailBod)
.deliver();
this.uploadService.wipeUserUploads(user).then(async () => {
await this.databaseService.write.uploads.deleteMany({
where: {
owner: user,
},
});
});
await this.databaseService.write.users.delete({
where: {
snowflake: user,
},
});
if (akey?.api_key) {
await this.databaseService.write.api_keys.delete({
where: {
api_key: akey.api_key,
},
});
}
return GenericRespEnum.ACCOUNT_DELETED;
}
}
interface PfpSetterArgs<Type extends PFP_TYPE> {
file: Type extends typeof PFP_TYPE.CUSTOM ? Buffer : undefined;
mime: Type extends typeof PFP_TYPE.CUSTOM ? string : undefined;
name: string;
user: string;
}