mirror of
https://github.com/gurucomputing/headscale-ui.git
synced 2026-01-23 02:34:43 +00:00
reorganised helper functions
This commit is contained in:
parent
0636ea9419
commit
e855f0694e
6 changed files with 193 additions and 181 deletions
52
src/lib/components/common/classes.svelte
Normal file
52
src/lib/components/common/classes.svelte
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<script module lang="ts">
|
||||
import { SvelteMap } from 'svelte/reactivity';
|
||||
|
||||
export class PersistentAppSettingsObject {
|
||||
daisyUITheme = ''; // for setting the UI theme. See https://daisyui.com/docs/themes/
|
||||
headscaleAPIKey = ''; // sensitive, allows for administrative access to headscale
|
||||
headscaleURL = ''; // url for headscale to use
|
||||
debugLogging = false; // to turn on additional messages
|
||||
|
||||
public constructor(init?: Partial<PersistentAppSettingsObject>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
export class AppSettingsObject {
|
||||
navbarTitle = ''; // for setting the title of the page
|
||||
appLoaded = false; // for hiding the screen until hydration has completed
|
||||
sidebarDrawerOpen = false; // for determining if the sidebar is open when on a small screen
|
||||
toastAlerts = new SvelteMap<string, toastAlert>(); // for adding or removing alerts
|
||||
apiTested = true; // used to hide the app if the api tests are failing
|
||||
apiKeyList: APIKey[] = []; //list of apikeys retrieved from headscale API
|
||||
apiKeyExpiration?: number = undefined; // number of days left until the key in use expires
|
||||
|
||||
public constructor(init?: Partial<AppSettingsObject>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
// alert used for populating toasts in the layout
|
||||
export class toastAlert {
|
||||
message = ''; //message to display
|
||||
notificationType = 'alert'; //to style the toast
|
||||
id = ''; //UUID generated to reference the toast
|
||||
|
||||
public constructor(init?: Partial<toastAlert>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
// retrieved as an array from headscale
|
||||
export class APIKey {
|
||||
id = ''; // unique identifier for headscale
|
||||
prefix = ''; // beginning of key to match full string
|
||||
expiration = ''; // when key expires, formatting as datetime
|
||||
createdAt = ''; // date of creation
|
||||
lastSeen = ''; // date last seen, seems to be always null?
|
||||
|
||||
public constructor(init?: Partial<APIKey>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
import { SvelteMap } from "svelte/reactivity";
|
||||
|
||||
export class PersistentAppSettingsObject {
|
||||
daisyUITheme = "" // for setting the UI theme. See https://daisyui.com/docs/themes/
|
||||
headscaleAPIKey = "" // sensitive, allows for administrative access to headscale
|
||||
headscaleURL = "" // url for headscale to use
|
||||
debugLogging = false // to turn on additional messages
|
||||
|
||||
public constructor(init?: Partial<PersistentAppSettingsObject>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
export class AppSettingsObject {
|
||||
navbarTitle = "" // for setting the title of the page
|
||||
appLoaded = false // for hiding the screen until hydration has completed
|
||||
sidebarDrawerOpen = false // for determining if the sidebar is open when on a small screen
|
||||
toastAlerts = new SvelteMap<string, toastAlert>(); // for adding or removing alerts
|
||||
apiTested = true // used to hide the app if the api tests are failing
|
||||
apiKeyList: APIKey[] = [] //list of apikeys retrieved from headscale API
|
||||
apiKeyExpiration?: number = undefined // number of days left until the key in use expires
|
||||
|
||||
public constructor(init?: Partial<AppSettingsObject>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
// alert used for populating toasts in the layout
|
||||
export class toastAlert {
|
||||
message = "" //message to display
|
||||
notificationType = "alert" //to style the toast
|
||||
id = "" //UUID generated to reference the toast
|
||||
|
||||
public constructor(init?: Partial<toastAlert>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
||||
// retrieved as an array from headscale
|
||||
export class APIKey {
|
||||
id = '' // unique identifier for headscale
|
||||
prefix = '' // beginning of key to match full string
|
||||
expiration = '' // when key expires, formatting as datetime
|
||||
createdAt = '' // date of creation
|
||||
lastSeen = '' // date last seen, seems to be always null?
|
||||
|
||||
public constructor(init?: Partial<APIKey>) {
|
||||
Object.assign(this, init);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
<script module lang=ts>
|
||||
import { appSettings } from "../common/state.svelte";
|
||||
import { toastAlert } from "../common/classes.svelte";
|
||||
|
||||
|
|
@ -7,4 +8,5 @@ export function newToastAlert(message: string) {
|
|||
id: uuid,
|
||||
message: message
|
||||
}));
|
||||
}
|
||||
}
|
||||
</script>
|
||||
137
src/lib/components/settings/server-settings-functions.svelte
Normal file
137
src/lib/components/settings/server-settings-functions.svelte
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<script module lang="ts">
|
||||
import { newToastAlert } from '../layout/toast-functions.svelte';
|
||||
import { appSettings, persistentAppSettings } from '../common/state.svelte';
|
||||
|
||||
export async function getAPIKeys() {
|
||||
try {
|
||||
const response = await fetch(`${persistentAppSettings.headscaleURL}/api/v1/apikey`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${persistentAppSettings.headscaleAPIKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
newToastAlert(`API test failed (check your server settings): ${response.status}`);
|
||||
appSettings.apiTested = false;
|
||||
} else {
|
||||
appSettings.apiKeyList = (await response.json()).apiKeys;
|
||||
appSettings.apiTested = true;
|
||||
|
||||
// determine the remaining time for the key we are currently using
|
||||
appSettings.apiKeyList.forEach((key) => {
|
||||
if (persistentAppSettings.headscaleAPIKey.startsWith(key.prefix)) {
|
||||
getKeyRemainingTime(new Date(key.expiration));
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
let message: string;
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else {
|
||||
message = String(error);
|
||||
}
|
||||
newToastAlert(`API test failed (check your server settings): ${message}`);
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getKeyRemainingTime(expiration: Date) {
|
||||
let currentTime = new Date();
|
||||
// gets time difference in seconds
|
||||
appSettings.apiKeyExpiration = Math.round((expiration.getTime() - currentTime.getTime()) / 1000 / 60 / 60 / 24);
|
||||
if (appSettings.apiKeyExpiration < 30) {
|
||||
newToastAlert(`${appSettings.apiKeyExpiration} days left before API Key expiry, consider rolling your key`);
|
||||
}
|
||||
}
|
||||
|
||||
export function rotateAPIKey() {
|
||||
appSettings.apiKeyList.forEach((key) => {
|
||||
// select the current key being used
|
||||
if (persistentAppSettings.headscaleAPIKey.startsWith(key.prefix)) {
|
||||
let currentKey = key;
|
||||
let newExpiration = new Date();
|
||||
newExpiration.setDate(newExpiration.getDate() + 90);
|
||||
|
||||
// create a new API key with the new new expiration, set it as the current API key,
|
||||
// and then expire the previous API key
|
||||
|
||||
createNewAPIKey(newExpiration).then((apiKey) => {
|
||||
if (apiKey == undefined) {
|
||||
throw new Error('expecting API key string, string was undefined');
|
||||
}
|
||||
persistentAppSettings.headscaleAPIKey = apiKey;
|
||||
expireAPIKey(currentKey.prefix).then(() => {
|
||||
getAPIKeys().then(() => {
|
||||
// console.log(appSettings.apiKeyList);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function createNewAPIKey(expireDate: Date) {
|
||||
try {
|
||||
const response = await fetch(`${persistentAppSettings.headscaleURL}/api/v1/apikey`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${persistentAppSettings.headscaleAPIKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
expiration: expireDate.toISOString()
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
newToastAlert(`Creating new API Key Failed (check your server settings): ${response.status}`);
|
||||
appSettings.apiTested = false;
|
||||
} else {
|
||||
let apiKey = '';
|
||||
apiKey = (await response.json()).apiKey;
|
||||
return apiKey;
|
||||
}
|
||||
} catch (error) {
|
||||
let message: string;
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else {
|
||||
message = String(error);
|
||||
}
|
||||
newToastAlert(`API Call Failed (check your server settings): ${message}`);
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function expireAPIKey(apiPrefix: string) {
|
||||
try {
|
||||
const response = await fetch(`${persistentAppSettings.headscaleURL}/api/v1/apikey/expire`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${persistentAppSettings.headscaleAPIKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
prefix: apiPrefix
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
newToastAlert(`API test failed (check your server settings): ${response.status}`);
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
} catch (error) {
|
||||
let message: string;
|
||||
if (error instanceof Error) {
|
||||
message = error.message;
|
||||
} else {
|
||||
message = String(error);
|
||||
}
|
||||
newToastAlert(`API test failed (check your server settings): ${message}`);
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
import { newToastAlert } from "../layout/toast.svelte.ts";
|
||||
import { appSettings, persistentAppSettings } from "../common/state.svelte";
|
||||
|
||||
export async function getAPIKeys() {
|
||||
try {
|
||||
const response = await fetch(`${persistentAppSettings.headscaleURL}/api/v1/apikey`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${persistentAppSettings.headscaleAPIKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
newToastAlert(`API test failed (check your server settings): ${response.status}`);
|
||||
appSettings.apiTested = false;
|
||||
} else {
|
||||
appSettings.apiKeyList = (await response.json()).apiKeys;
|
||||
appSettings.apiTested = true;
|
||||
|
||||
// determine the remaining time for the key we are currently using
|
||||
appSettings.apiKeyList.forEach(key => {
|
||||
if (persistentAppSettings.headscaleAPIKey.startsWith(key.prefix)) {
|
||||
getKeyRemainingTime(new Date(key.expiration));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
let message: string;
|
||||
if (error instanceof Error) { message = error.message }
|
||||
else { message = String(error) }
|
||||
newToastAlert(`API test failed (check your server settings): ${message}`)
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getKeyRemainingTime(expiration: Date) {
|
||||
let currentTime = new Date();
|
||||
// gets time difference in seconds
|
||||
appSettings.apiKeyExpiration = Math.round((expiration.getTime() - currentTime.getTime()) / 1000 / 60 / 60 / 24);
|
||||
if (appSettings.apiKeyExpiration < 30) {
|
||||
newToastAlert(`${appSettings.apiKeyExpiration} days left before API Key expiry, consider rolling your key`);
|
||||
}
|
||||
}
|
||||
|
||||
export function rotateAPIKey() {
|
||||
appSettings.apiKeyList.forEach(key => {
|
||||
// select the current key being used
|
||||
if (persistentAppSettings.headscaleAPIKey.startsWith(key.prefix)) {
|
||||
let currentKey = key;
|
||||
let newExpiration = new Date();
|
||||
newExpiration.setDate(newExpiration.getDate() + 90);
|
||||
|
||||
// create a new API key with the new new expiration, set it as the current API key,
|
||||
// and then expire the previous API key
|
||||
|
||||
createNewAPIKey(newExpiration).then((apiKey) => {
|
||||
if (apiKey == undefined) {
|
||||
throw new Error("expecting API key string, string was undefined");
|
||||
}
|
||||
persistentAppSettings.headscaleAPIKey = apiKey;
|
||||
expireAPIKey(currentKey.prefix).then(() => {
|
||||
getAPIKeys().then(() => {
|
||||
// console.log(appSettings.apiKeyList);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function createNewAPIKey(expireDate: Date) {
|
||||
try {
|
||||
const response = await fetch(`${persistentAppSettings.headscaleURL}/api/v1/apikey`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${persistentAppSettings.headscaleAPIKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"expiration": expireDate.toISOString()
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
newToastAlert(`Creating new API Key Failed (check your server settings): ${response.status}`);
|
||||
appSettings.apiTested = false;
|
||||
} else {
|
||||
let apiKey = '';
|
||||
apiKey = (await response.json()).apiKey;
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
let message: string;
|
||||
if (error instanceof Error) { message = error.message }
|
||||
else { message = String(error) }
|
||||
newToastAlert(`API Call Failed (check your server settings): ${message}`)
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function expireAPIKey(apiPrefix: string) {
|
||||
try {
|
||||
const response = await fetch(`${persistentAppSettings.headscaleURL}/api/v1/apikey/expire`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${persistentAppSettings.headscaleAPIKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"prefix": apiPrefix
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
newToastAlert(`API test failed (check your server settings): ${response.status}`);
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
let message: string;
|
||||
if (error instanceof Error) { message = error.message }
|
||||
else { message = String(error) }
|
||||
newToastAlert(`API test failed (check your server settings): ${message}`)
|
||||
appSettings.apiTested = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { persistentAppSettings } from '$lib/components/common/state.svelte';
|
||||
import { getAPIKeys, rotateAPIKey } from './server-settings-functions.svelte.ts';
|
||||
import { getAPIKeys, rotateAPIKey } from './server-settings-functions.svelte';
|
||||
import { appSettings } from '$lib/components/common/state.svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue