Build base web

This commit is contained in:
2023-09-04 14:11:56 +02:00
parent 83bd87c6f8
commit 8defc104c6
35 changed files with 31630 additions and 0 deletions

View File

@ -0,0 +1,82 @@
import { AuthApi } from "./AuthApi";
interface APIResponse {
data: any;
status: number;
}
export class ApiError extends Error {
constructor(message: string, public code: number, public data: any) {
super(message);
}
}
export class APIClient {
/**
* Get backend URL
*/
static backendURL(): string {
const URL = process.env.REACT_APP_BACKEND ?? "";
if (URL.length === 0) throw new Error("Backend URL undefined!");
return URL;
}
/**
* Check out whether the backend is accessed through
* HTTPS or not
*/
static IsBackendSecure(): boolean {
return this.backendURL().startsWith("https");
}
/**
* Perform a request on the backend
*/
static async exec(args: {
uri: string;
method: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
allowFail?: boolean;
jsonData?: any;
formData?: FormData;
}): Promise<APIResponse> {
let body = undefined;
let headers: any = {};
// JSON request
if (args.jsonData) {
headers["Content-Type"] = "application/json";
body = JSON.stringify(args.jsonData);
}
// Form data request
else if (args.formData) {
body = args.formData;
}
const res = await fetch(this.backendURL() + args.uri, {
method: args.method,
body: body,
headers: headers,
});
// Process response
let data;
if (res.headers.get("content-type") === "application/json")
data = await res.json();
else data = await res.blob();
// Handle expired tokens
if (res.status === 412) {
AuthApi.UnsetAuthenticated();
window.location.href = "/";
}
if (!args.allowFail && !res.ok)
throw new ApiError("Request failed!", res.status, data);
return {
data: data,
status: res.status,
};
}
}

View File

@ -0,0 +1,86 @@
import { APIClient } from "./ApiClient";
const TokenStateKey = "auth-state";
export class AuthApi {
/**
* Check out whether user is signed in or not
*/
static get SignedIn(): boolean {
return localStorage.getItem(TokenStateKey) !== null;
}
/**
* Mark user as authenticated
*/
static SetAuthenticated() {
localStorage.setItem(TokenStateKey, "");
}
/**
* Un-mark user as authenticated
*/
static UnsetAuthenticated() {
localStorage.removeItem(TokenStateKey);
}
/**
* Authenticate using an username and a password
*
* @param username The username to use
* @param password The password to use
*/
static async LoginWithPassword(
username: string,
password: string
): Promise<void> {
await APIClient.exec({
uri: "/auth/local",
method: "POST",
allowFail: true,
jsonData: {
username: username,
password: password,
},
});
this.SetAuthenticated();
}
/**
* Start OpenID login
*/
static async StartOpenIDLogin(): Promise<{ url: string }> {
return (
await APIClient.exec({
uri: "/auth/start_oidc",
method: "GET",
})
).data;
}
/**
* Finish OpenID login
*/
static async FinishOpenIDLogin(code: string, state: string): Promise<void> {
await APIClient.exec({
uri: "/auth/finish_oidc",
method: "POST",
jsonData: { code: code, state: state },
});
this.SetAuthenticated();
}
/**
* Sign out
*/
static async SignOut(): Promise<void> {
await APIClient.exec({
uri: "/auth/sign_out",
method: "GET",
});
this.UnsetAuthenticated();
}
}

View File

@ -0,0 +1,30 @@
import { APIClient } from "./ApiClient";
export interface ServerConfig {
local_auth_enabled: boolean;
oidc_auth_enabled: boolean;
}
let config: ServerConfig | null = null;
export class ServerApi {
/**
* Get server configuration
*/
static async LoadConfig(): Promise<void> {
config = (
await APIClient.exec({
uri: "/server/static_config",
method: "GET",
})
).data;
}
/**
* Get cached configuration
*/
static get Config(): ServerConfig {
if (config === null) throw new Error("Missing configuration!");
return config;
}
}