forked from zombieb/galvanic-corrosion-rewrite
170 lines
7.2 KiB
TypeScript
170 lines
7.2 KiB
TypeScript
import z from "zod";
|
|
import Command from "../commands/command.ts";
|
|
import { ServerContentBase } from "../ContentBase.ts";
|
|
import { transformCheckEnum } from "../../util/validators.ts";
|
|
import { sign } from "@hono/hono/jwt";
|
|
import { CachedLogin, DbCachedLogin, PlatformMask, PlatformType, TokenFormat, TokenType } from "./types.ts";
|
|
import type Profile from "../profiles/profile.ts";
|
|
import { getNetConfig } from "../../net.ts";
|
|
|
|
export const steamAuthTicketSchema = z.object({
|
|
Ticket: z.string().min(256),
|
|
AppId: z.literal("471710")
|
|
});
|
|
|
|
const netConfig = getNetConfig();
|
|
|
|
export class PlatformsManager extends ServerContentBase {
|
|
|
|
static platformsKey = "platforms";
|
|
|
|
#constructPlatformKey(...keys: (string | number | undefined)[]) {
|
|
return [PlatformsManager.platformsKey, ...keys.filter(val => typeof val == 'string')];
|
|
}
|
|
|
|
async getToken(prof: Profile, type: TokenType) {
|
|
const secret = Deno.env.get('SECRET');
|
|
if (!secret) throw new Error("No SECRET in env. Did you forget to set it?");
|
|
const exp = type == TokenType.Access ? Math.round(Date.now() / 1000) + 21_600 : Math.round(Date.now() / 1000) + 31_556_952;
|
|
|
|
const token: TokenFormat = {
|
|
typ: type,
|
|
sub: prof.getId(),
|
|
role: await prof.getRole(),
|
|
iss: `${netConfig.securePublicHost ? "https" : "http"}://${netConfig.publicHost}/auth`,
|
|
iat: Math.round(Date.now() / 1000) - 5,
|
|
exp
|
|
}
|
|
return await sign(JSON.parse(JSON.stringify(token)), secret);
|
|
}
|
|
|
|
async updateLastLoginTime(platform: PlatformType, platformId: string, accountId: number) {
|
|
const key = this.#constructPlatformKey(platform, platformId);
|
|
const set = await this.kv.getKv().get<Set<DbCachedLogin>>(key);
|
|
|
|
if (set.value) {
|
|
const existing = set.value.values().toArray().find(val => val.accountId == accountId);
|
|
if (!existing) return;
|
|
|
|
existing.lastLoginTime = new Date();
|
|
await this.kv.getKv().set(key, set.value);
|
|
}
|
|
}
|
|
|
|
async addCachedLogin(platform: PlatformType, platformId: string, accountId: number) {
|
|
const key = this.#constructPlatformKey(platform, platformId);
|
|
const set = await this.kv.getKv().get<Set<DbCachedLogin>>(key);
|
|
|
|
if (set.value) {
|
|
const existing = set.value.values().toArray().find(val => val.accountId == accountId);
|
|
if (!existing) {
|
|
set.value.add({ accountId, lastLoginTime: new Date(), requirePassword: false });
|
|
await this.kv.getKv().set(key, set.value);
|
|
}
|
|
|
|
return set.value.values().toArray();
|
|
} else {
|
|
const newSet = new Set<DbCachedLogin>([{ accountId, lastLoginTime: new Date(), requirePassword: false }]);
|
|
await this.kv.getKv().set(key, newSet);
|
|
return newSet.values().toArray();
|
|
};
|
|
}
|
|
|
|
async getCachedLogins(platform: PlatformType, platformId: string, format: true): Promise<CachedLogin[]>
|
|
async getCachedLogins(platform: PlatformType, platformId: string, format: false): Promise<DbCachedLogin[]>
|
|
async getCachedLogins(platform: PlatformType, platformId: string, format?: boolean) {
|
|
const set = await this.kv.getKv().get<Set<DbCachedLogin>>(this.#constructPlatformKey(platform, platformId));
|
|
if (set.value && format) return set.value.values().toArray().map(val => ({
|
|
platform,
|
|
platformId,
|
|
accountId: val.accountId,
|
|
lastLoginTime: val.lastLoginTime,
|
|
requirePassword: val.requirePassword
|
|
} as CachedLogin));
|
|
else if (set.value) return set.value.values().toArray();
|
|
else return [];
|
|
}
|
|
|
|
async deleteCachedLogin(platform: PlatformType, platformId: string, accountId: number) {
|
|
const key = this.#constructPlatformKey(platform, platformId);
|
|
const set = await this.kv.getKv().get<Set<DbCachedLogin>>(key);
|
|
|
|
if (set.value) {
|
|
const existing = set.value.values().toArray().find(val => val.accountId == accountId);
|
|
if (existing) {
|
|
set.value.delete(existing);
|
|
await this.kv.getKv().set(key, set.value);
|
|
}
|
|
|
|
return set.value.values().toArray();
|
|
} else return null;
|
|
}
|
|
|
|
getPlatformMask(value: number) {
|
|
const err = new Error("Invalid mask");
|
|
if (typeof value !== 'number' || !Number.isInteger(value)) throw err;
|
|
|
|
if (value === PlatformMask.All) {
|
|
return [PlatformMask.All];
|
|
}
|
|
|
|
return Object.values(PlatformMask)
|
|
.filter(v => typeof v === "number" && v !== PlatformMask.None && v !== PlatformMask.All)
|
|
.filter(v => (value & (v as number)) === v) as PlatformMask[];
|
|
}
|
|
|
|
buildPlatformMask(...flags: PlatformMask[]) {
|
|
const err = new Error("Invalid mask");
|
|
if (!flags.length) throw err;
|
|
|
|
for (const flag of flags)
|
|
if (typeof flag !== 'number' || !Object.values(PlatformMask).includes(flag))
|
|
throw err;
|
|
|
|
return flags.reduce((mask, flag) => mask | flag, 0);
|
|
}
|
|
|
|
override start() {
|
|
this.server.Commands.addRootCommand(new Command({
|
|
key: ['platforms', 'pm', 'platformmanager', 'platformanager'],
|
|
subcommands: [
|
|
new Command({
|
|
key: ['get', 'g', 'list', 'l'],
|
|
exec: async (type: PlatformType, platformId: string) => {
|
|
return await this.getCachedLogins(type, platformId, false);
|
|
},
|
|
zod: z.tuple([
|
|
z.coerce.number().transform(transformCheckEnum<PlatformType>(PlatformType)),
|
|
z.string().min(4)
|
|
]),
|
|
help: 'List all cachedlogins for platformId: <type: PlatformType, platformId: string>'
|
|
}),
|
|
new Command({
|
|
key: ['set', 's', 'add', 'a'],
|
|
exec: async (type: PlatformType, platformId: string, accountId: number) => {
|
|
return await this.addCachedLogin(type, platformId, accountId);
|
|
},
|
|
zod: z.tuple([
|
|
z.coerce.number().transform(transformCheckEnum<PlatformType>(PlatformType)),
|
|
z.string(),
|
|
z.coerce.number()
|
|
]),
|
|
help: 'Add a cachedlogin for platformId: <type: PlatformType>, <platformId: string>, <accountId: number>'
|
|
}),
|
|
new Command({
|
|
key: ['del', 'd', 'rem', 'remove', 'r'],
|
|
exec: async (type: PlatformType, platformId: string, accountId: number) => {
|
|
return await this.deleteCachedLogin(type, platformId, accountId);
|
|
},
|
|
zod: z.tuple([
|
|
z.coerce.number().transform(transformCheckEnum<PlatformType>(PlatformType)),
|
|
z.string(),
|
|
z.coerce.number()
|
|
]),
|
|
help: 'Remove a cachedlogin for platformId: <type: PlatformType>, <platformId: string>, <accountId: number>'
|
|
})
|
|
]
|
|
}));
|
|
}
|
|
|
|
} |