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
|
* Get Skyblock profiles by player
|
||||||
* @param key API key
|
* @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
|
* @returns A fetch-like function
|
||||||
*/
|
*/
|
||||||
export function requestWithDefaults(
|
export function requestWithDefaults(
|
||||||
baseURL: string,
|
baseURL?: string,
|
||||||
defaultInit?: RequestInit
|
defaultInit?: RequestInit
|
||||||
): (endpoint: string, init?: RequestInit) => Promise<Response> {
|
): (endpoint: string, init?: RequestInit) => Promise<Response> {
|
||||||
return async function (
|
return async function (
|
||||||
|
@ -24,7 +24,7 @@ export function requestWithDefaults(
|
||||||
overrideInit?: RequestInit
|
overrideInit?: RequestInit
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
let response = await getFetch()(
|
let response = await getFetch()(
|
||||||
new URL(endpoint, baseURL).href,
|
baseURL ? new URL(endpoint, baseURL).href : endpoint,
|
||||||
defaultInit ? deepMerge(defaultInit, overrideInit) : overrideInit
|
defaultInit ? deepMerge(defaultInit, overrideInit) : overrideInit
|
||||||
);
|
);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
|
Loading…
Reference in New Issue