128 lines
4.9 KiB
TypeScript
128 lines
4.9 KiB
TypeScript
import { Redis } from "../db.ts";
|
|
import Dictionary from "./usernames.ts";
|
|
import { Config } from "../config.ts";
|
|
import { AuthType } from "./users.ts";
|
|
import * as JsonWebToken from "@gz/jwt";
|
|
|
|
const config = Config.getConfig();
|
|
|
|
interface ProfileInitOptions {
|
|
username: string
|
|
}
|
|
interface AccountExport {
|
|
accountId: number,
|
|
profileImage: string,
|
|
isJunior: boolean,
|
|
platforms: number,
|
|
username: string,
|
|
displayName: string
|
|
}
|
|
export type ProfileTokenFormat = {
|
|
iss: string;
|
|
sub: number;
|
|
nbf: number;
|
|
iat: number;
|
|
exp: number;
|
|
typ: AuthType;
|
|
}
|
|
|
|
class Profile {
|
|
|
|
static async getUniqueId() {
|
|
let id = Math.round(Math.random() * Math.pow(2, 31));
|
|
while ((await Redis.Database.exists(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Username))) >= 1)
|
|
id = await this.getUniqueId();
|
|
return id;
|
|
}
|
|
|
|
static async byName(name: string) {
|
|
const id = await Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profile_Usernames, name));
|
|
if (id == null) return null;
|
|
else return new Profile(parseInt(id, 10));
|
|
}
|
|
|
|
static async getUniqueUsername() {
|
|
let username = `${Dictionary.Adjectives[Math.floor(Math.random() * Dictionary.Adjectives.length)]}${Dictionary.Nouns[Math.floor(Math.random() * Dictionary.Nouns.length)]}${Math.round(Math.random() * 10000)}`
|
|
while ((await Profile.byName(username)) !== null) username = await this.getUniqueUsername();
|
|
return username;
|
|
}
|
|
|
|
static async init(options?: ProfileInitOptions) {
|
|
|
|
const optionsSpecified = typeof options !== 'undefined';
|
|
|
|
const newId = await this.getUniqueId();
|
|
const newUsername = optionsSpecified ? options.username : await this.getUniqueUsername();
|
|
|
|
await Redis.Database.set(Redis.buildKey(Redis.KeyGroups.Profile_Usernames, newUsername), newId);
|
|
await Redis.Database.set(Redis.buildKey(Redis.KeyGroups.Profiles.Root, newId.toString(), Redis.KeyGroups.Profiles.Username), newUsername);
|
|
|
|
return new Profile(newId);
|
|
|
|
}
|
|
|
|
// surely this can be written better
|
|
static getExportAccount(id: number): Promise<AccountExport | null> {
|
|
return new Promise((resolve, _reject) => {
|
|
Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Username)).then(val => {
|
|
if (val == null) resolve(null);
|
|
else {
|
|
const promises = {
|
|
profileImage: Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.ProfileImage)),
|
|
isJunior: Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Junior)),
|
|
platforms: Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Platforms)),
|
|
displayName: Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.DisplayName)),
|
|
username: Redis.Database.get(Redis.buildKey(Redis.KeyGroups.Profiles.Root, id.toString(), Redis.KeyGroups.Profiles.Username)),
|
|
}
|
|
|
|
Promise.all(Object.values(promises)).then((values) => {
|
|
resolve({
|
|
accountId: id,
|
|
profileImage: values[0] == null ? "DefaultProfileImage" : values[0],
|
|
isJunior: values[1] == null ? false : JSON.parse(values[1]),
|
|
platforms: values[2] == null ? 1 : JSON.parse(values[2]),
|
|
displayName: values[3] == null ? (values[4] == null ? "DATABASEERROR" : values[4]) : values[3],
|
|
username: values[4] == null ? "DATABASEERROR" : values[4],
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
static async getExportAccountsBulk(ids: number[]) {
|
|
|
|
const accs = await Promise.all(ids.map(val => this.getExportAccount(val)));
|
|
return accs.filter(val => val !== null);
|
|
|
|
}
|
|
|
|
#id: number;
|
|
|
|
constructor(id: number) {
|
|
this.#id = id;
|
|
}
|
|
|
|
getId() {
|
|
return this.#id;
|
|
}
|
|
|
|
async export() {
|
|
return await Profile.getExportAccount(this.#id);
|
|
}
|
|
|
|
async getToken() {
|
|
const payload: ProfileTokenFormat = {
|
|
iss: config.web.publichost,
|
|
sub: this.#id,
|
|
nbf: Math.round(Date.now() / 1000) - 200,
|
|
iat: Math.round(Date.now() / 1000),
|
|
exp: Math.round(Date.now() / 1000) + (config.auth.timeout * 60 * 60),
|
|
typ: AuthType.Web
|
|
};
|
|
return await JsonWebToken.encode(payload, config.auth.secret, { algorithm: "HS512" });
|
|
}
|
|
|
|
}
|
|
|
|
export default Profile; |