lib
This commit is contained in:
parent
cf5b1a2ce2
commit
04dba57520
|
@ -0,0 +1,121 @@
|
|||
import type { Graph, Tracker } from "../routes/api/_types";
|
||||
import type { Profile } from "./hypixel";
|
||||
import { requestWithDefaults } from "./util";
|
||||
|
||||
const request = requestWithDefaults();
|
||||
|
||||
/**
|
||||
* Login into SBDataTracker backend
|
||||
* @param params Login parameters (no parameters = refresh)
|
||||
* @returns Login details
|
||||
*/
|
||||
export async function postLogin(params?: {
|
||||
username: string;
|
||||
password: string;
|
||||
}): Promise<{
|
||||
token: string;
|
||||
username: string;
|
||||
expires: number;
|
||||
}> {
|
||||
let url = "/api/login";
|
||||
if (params) {
|
||||
url += `?username=${encodeURIComponent(
|
||||
params.username
|
||||
)}&password=${encodeURIComponent(params.password)}`;
|
||||
}
|
||||
let response = await request(url, { method: "POST" });
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @param token Authorization token
|
||||
*/
|
||||
export async function postLogout(token: string) {
|
||||
await request("/api/logout", {
|
||||
method: "POST",
|
||||
headers: { Authorization: token }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of profiles
|
||||
* @param token Authorization token
|
||||
* @returns A list of profiles
|
||||
*/
|
||||
export async function getProfiles(
|
||||
token?: string
|
||||
): Promise<(Tracker & { profile: string })[]> {
|
||||
let response = await request(
|
||||
"/api/profiles",
|
||||
token ? { headers: { Authorization: token } } : {}
|
||||
);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of skyblock profiles by player
|
||||
* @param player Player's UUID
|
||||
* @returns A list of profiles
|
||||
*/
|
||||
export async function getPlayerProfiles(player: string): Promise<Profile[]> {
|
||||
let response = await request(`/api/profiles/${player}`);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of graphs
|
||||
* @param token Authorization token
|
||||
* @returns A list of profiles
|
||||
*/
|
||||
export async function getGraphs(
|
||||
token?: string
|
||||
): Promise<(Graph & { graph: string })[]> {
|
||||
let response = await request(
|
||||
"/api/graphs",
|
||||
token ? { headers: { Authorization: token } } : {}
|
||||
);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player username by UUID
|
||||
* @param uuid Player's UUID
|
||||
* @returns Player's username
|
||||
*/
|
||||
export async function getUsername(uuid: string): Promise<string> {
|
||||
let response = await request(`/api/username?uuid=${uuid}`);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player UUID by username
|
||||
* @param username Player's username
|
||||
* @returns Player's UUID
|
||||
*/
|
||||
export async function getUUID(username: string): Promise<string> {
|
||||
let response = await request(`/api/uuid?username=${username}`);
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a profile
|
||||
* @param token Authorization token
|
||||
* @param uuid Profile UUID
|
||||
* @param member Member to assign the profile to
|
||||
* @returns Tracker information
|
||||
*/
|
||||
export async function putProfiles(
|
||||
token: string | undefined,
|
||||
uuid: string,
|
||||
member?: string
|
||||
): Promise<Tracker & { _key: string }> {
|
||||
let response = await request(
|
||||
`/api/profiles?uuid=${uuid}` + (member ? `&member=${member}` : ""),
|
||||
{
|
||||
method: "PUT",
|
||||
...(token ? { headers: { Authorization: token } } : {})
|
||||
}
|
||||
);
|
||||
return response.json();
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
import { aql, Database } from "arangojs";
|
||||
import type { Document } from "arangojs/documents";
|
||||
import { compare } from "bcrypt";
|
||||
import type { IncomingMessage, ServerResponse } from "http";
|
||||
import type { Session, User } from "../routes/api/_types";
|
||||
import { checkPermissions } from "./permissions";
|
||||
|
||||
/**
|
||||
* Find a session in a database
|
||||
* @param db Arango database
|
||||
* @param token Session token
|
||||
* @returns The session data
|
||||
*/
|
||||
export async function findSession(
|
||||
db: Database,
|
||||
token: string
|
||||
): Promise<Document<Session> | null> {
|
||||
if (token) {
|
||||
const cursor = await db.query(aql`
|
||||
FOR session IN sessions
|
||||
RETURN session
|
||||
`);
|
||||
while (cursor.hasNext) {
|
||||
let doc = await cursor.next();
|
||||
if (await compare(token, doc.token)) {
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find authorizing user
|
||||
* @param db Arango database
|
||||
* @param token Session token
|
||||
* @returns The user data
|
||||
*/
|
||||
export async function findAuthorizer(
|
||||
db: Database,
|
||||
token?: string
|
||||
): Promise<(Document<User> & { _session?: Document<Session> }) | null> {
|
||||
const session = await findSession(db, token || "");
|
||||
if (!session?.user) {
|
||||
const cursor = await db.query(aql`
|
||||
FOR user IN users
|
||||
FILTER user.username == "_guest"
|
||||
LIMIT 1
|
||||
RETURN user
|
||||
`);
|
||||
if (cursor.hasNext) {
|
||||
return cursor.next();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
const users = db.collection("users");
|
||||
try {
|
||||
let user = await users.document(session?.user);
|
||||
user._session = session;
|
||||
return user;
|
||||
} catch (e) {
|
||||
throw new Error("Invalid user");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AuthorizationReturn<T extends true | false = boolean> = T extends true
|
||||
? [null, T]
|
||||
: [Document<User> & { _token?: string; _session?: Document<Session> }, T];
|
||||
/**
|
||||
* Authorize a user
|
||||
* @param req Request
|
||||
* @param res Response
|
||||
* @param db Arango database
|
||||
* @param permissions The permissions to check against
|
||||
* @returns The user and whether to return
|
||||
*/
|
||||
export async function authorizeRequest(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
db: Database,
|
||||
permissions: string[]
|
||||
): Promise<AuthorizationReturn> {
|
||||
const token = req.headers.authorization;
|
||||
let user:
|
||||
| (Document<User> & { _token?: string; _session?: Document<Session> })
|
||||
| null;
|
||||
try {
|
||||
user = await findAuthorizer(db, token);
|
||||
} catch (e) {
|
||||
res.writeHead(401);
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
message: "Invalid user"
|
||||
})
|
||||
);
|
||||
return [null, true];
|
||||
}
|
||||
if (user === null) {
|
||||
res.writeHead(500);
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
message: "_guest user not found"
|
||||
})
|
||||
);
|
||||
return [null, true];
|
||||
}
|
||||
|
||||
if (!checkPermissions(permissions, user.permissions)) {
|
||||
res.writeHead(403);
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
message: "Missing permissions"
|
||||
})
|
||||
);
|
||||
return [null, true];
|
||||
}
|
||||
|
||||
user._token = token;
|
||||
return [user, false];
|
||||
}
|
|
@ -31,6 +31,14 @@ export async function getAPIKeyInformation(key: string): Promise<
|
|||
};
|
||||
}
|
||||
|
||||
export type Profile = {
|
||||
profile_id: string;
|
||||
members: any;
|
||||
community_upgrades: any | null;
|
||||
cute_name: string;
|
||||
banking: any | null;
|
||||
game_mode: string | null;
|
||||
};
|
||||
/**
|
||||
* Get Skyblock profiles by player
|
||||
* @param key API key
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { requestWithDefaults } from "./util";
|
||||
|
||||
export const ENDPOINT = "https://api.mojang.com/";
|
||||
const request = requestWithDefaults(ENDPOINT);
|
||||
|
||||
/**
|
||||
* Get a Minecraft username by UUID
|
||||
* @param uuid Player's UUID
|
||||
* @returns A username
|
||||
*/
|
||||
export async function getUsernameByUUID(uuid: string): Promise<string> {
|
||||
let response = await request(`/user/profile/${uuid}`);
|
||||
return (await response.json()).name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Minecraft UUID by username
|
||||
* @param name Player's username
|
||||
* @returns A UUID
|
||||
*/
|
||||
export async function getUUIDByUsername(name: string): Promise<string> {
|
||||
let response = await request(`/users/profiles/minecraft/${name}`);
|
||||
return (await response.json()).id;
|
||||
}
|
|
@ -16,7 +16,7 @@ export function getFetch(): typeof fetch {
|
|||
* @returns A fetch-like function
|
||||
*/
|
||||
export function requestWithDefaults(
|
||||
baseURL: string,
|
||||
baseURL?: string,
|
||||
defaultInit?: RequestInit
|
||||
): (endpoint: string, init?: RequestInit) => Promise<Response> {
|
||||
return async function (
|
||||
|
@ -24,7 +24,7 @@ export function requestWithDefaults(
|
|||
overrideInit?: RequestInit
|
||||
): Promise<Response> {
|
||||
let response = await getFetch()(
|
||||
new URL(endpoint, baseURL).href,
|
||||
baseURL ? new URL(endpoint, baseURL).href : endpoint,
|
||||
defaultInit ? deepMerge(defaultInit, overrideInit) : overrideInit
|
||||
);
|
||||
if (response.ok) {
|
||||
|
|
Loading…
Reference in New Issue