work
This commit is contained in:
parent
f4c0a1718e
commit
f52db518e7
|
@ -0,0 +1,12 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {t} from "svelte-i18n";
|
||||||
|
|
||||||
|
export let selected;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button disabled="{selected === 'hosts'}" on:click={() => {window.location.href="/hosts"}}>{$t("common.page.hosts")}</button>
|
||||||
|
<button disabled="{selected === 'lighthouses'}" on:click={() => {window.location.href="/lighthouses"}}>{$t("common.page.lighthouses")}</button>
|
||||||
|
<button disabled="{selected === 'relays'}" on:click={() => {window.location.href="/relays"}}>{$t("common.page.relays")}</button>
|
||||||
|
<button disabled="{selected === 'roles'}" on:click={() => {window.location.href="/roles"}}>{$t("common.page.roles")}</button>
|
||||||
|
</div>
|
|
@ -12,43 +12,43 @@
|
||||||
* Do not edit the class manually.
|
* Do not edit the class manually.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type {ActorAPIKey} from './ActorAPIKey';
|
||||||
import {
|
import {
|
||||||
ActorAPIKey,
|
|
||||||
instanceOfActorAPIKey,
|
instanceOfActorAPIKey,
|
||||||
ActorAPIKeyFromJSON,
|
ActorAPIKeyFromJSON,
|
||||||
ActorAPIKeyFromJSONTyped,
|
ActorAPIKeyFromJSONTyped,
|
||||||
ActorAPIKeyToJSON,
|
ActorAPIKeyToJSON,
|
||||||
} from './ActorAPIKey';
|
} from './ActorAPIKey';
|
||||||
|
import type {ActorHost} from './ActorHost';
|
||||||
import {
|
import {
|
||||||
ActorHost,
|
|
||||||
instanceOfActorHost,
|
instanceOfActorHost,
|
||||||
ActorHostFromJSON,
|
ActorHostFromJSON,
|
||||||
ActorHostFromJSONTyped,
|
ActorHostFromJSONTyped,
|
||||||
ActorHostToJSON,
|
ActorHostToJSON,
|
||||||
} from './ActorHost';
|
} from './ActorHost';
|
||||||
|
import type {ActorOIDCUser} from './ActorOIDCUser';
|
||||||
import {
|
import {
|
||||||
ActorOIDCUser,
|
|
||||||
instanceOfActorOIDCUser,
|
instanceOfActorOIDCUser,
|
||||||
ActorOIDCUserFromJSON,
|
ActorOIDCUserFromJSON,
|
||||||
ActorOIDCUserFromJSONTyped,
|
ActorOIDCUserFromJSONTyped,
|
||||||
ActorOIDCUserToJSON,
|
ActorOIDCUserToJSON,
|
||||||
} from './ActorOIDCUser';
|
} from './ActorOIDCUser';
|
||||||
|
import type {ActorSupport} from './ActorSupport';
|
||||||
import {
|
import {
|
||||||
ActorSupport,
|
|
||||||
instanceOfActorSupport,
|
instanceOfActorSupport,
|
||||||
ActorSupportFromJSON,
|
ActorSupportFromJSON,
|
||||||
ActorSupportFromJSONTyped,
|
ActorSupportFromJSONTyped,
|
||||||
ActorSupportToJSON,
|
ActorSupportToJSON,
|
||||||
} from './ActorSupport';
|
} from './ActorSupport';
|
||||||
|
import type {ActorSystem} from './ActorSystem';
|
||||||
import {
|
import {
|
||||||
ActorSystem,
|
|
||||||
instanceOfActorSystem,
|
instanceOfActorSystem,
|
||||||
ActorSystemFromJSON,
|
ActorSystemFromJSON,
|
||||||
ActorSystemFromJSONTyped,
|
ActorSystemFromJSONTyped,
|
||||||
ActorSystemToJSON,
|
ActorSystemToJSON,
|
||||||
} from './ActorSystem';
|
} from './ActorSystem';
|
||||||
|
import type {ActorUser} from './ActorUser';
|
||||||
import {
|
import {
|
||||||
ActorUser,
|
|
||||||
instanceOfActorUser,
|
instanceOfActorUser,
|
||||||
ActorUserFromJSON,
|
ActorUserFromJSON,
|
||||||
ActorUserFromJSONTyped,
|
ActorUserFromJSONTyped,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Logger, logSetup} from "$lib/logger";
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
import {PUBLIC_BASE_URL} from "$env/static/public";
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
|
||||||
export enum AuthResult {
|
export enum APIResult {
|
||||||
Failed = 0,
|
Failed = 0,
|
||||||
Successful = 1
|
Successful = 1
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ export interface APIError {
|
||||||
logSetup();
|
logSetup();
|
||||||
const logger = new Logger("auth.ts");
|
const logger = new Logger("auth.ts");
|
||||||
|
|
||||||
export async function isAuthedSession(): Promise<[AuthResult, SessionInfo | APIError]> {
|
export async function isAuthedSession(): Promise<[APIResult, SessionInfo | APIError]> {
|
||||||
logger.info('Checking for session authentication');
|
logger.info('Checking for session authentication');
|
||||||
|
|
||||||
if (window.localStorage.getItem("session") === null) {
|
if (window.localStorage.getItem("session") === null) {
|
||||||
logger.error('unable to check session: session token not set');
|
logger.error('unable to check session: session token not set');
|
||||||
return [AuthResult.Failed, {code: "missing_token", message: "not logged in"}];
|
return [APIResult.Failed, {code: "missing_token", message: "not logged in"}];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -41,27 +41,27 @@ export async function isAuthedSession(): Promise<[AuthResult, SessionInfo | APIE
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error fetching user information: ${rawerror.message}`);
|
logger.error(`error fetching user information: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
return [AuthResult.Successful, JSON.parse(await resp.text()).data.actor]
|
return [APIResult.Successful, JSON.parse(await resp.text()).data.actor]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function isAuthedMFA(): Promise<[AuthResult, SessionInfo | APIError]> {
|
export async function isAuthedMFA(): Promise<[APIResult, SessionInfo | APIError]> {
|
||||||
logger.info('Checking for MFA authentication');
|
logger.info('Checking for MFA authentication');
|
||||||
|
|
||||||
if (window.localStorage.getItem("mfa") === null) {
|
if (window.localStorage.getItem("mfa") === null) {
|
||||||
logger.error('unable to check mfa: mfa token not set');
|
logger.error('unable to check mfa: mfa token not set');
|
||||||
return [AuthResult.Failed, {code: "missing_token", message: "not logged in"}];
|
return [APIResult.Failed, {code: "missing_token", message: "not logged in"}];
|
||||||
}
|
}
|
||||||
|
|
||||||
const sess = await isAuthedSession();
|
const sess = await isAuthedSession();
|
||||||
if (sess[0] !== AuthResult.Successful) {
|
if (sess[0] !== APIResult.Successful) {
|
||||||
logger.error('unable to check mfa: session token invalid');
|
logger.error('unable to check mfa: session token invalid');
|
||||||
return [AuthResult.Failed, sess[1]];
|
return [APIResult.Failed, sess[1]];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -75,16 +75,16 @@ export async function isAuthedMFA(): Promise<[AuthResult, SessionInfo | APIError
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error fetching user information: ${rawerror.message}`);
|
logger.error(`error fetching user information: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
return [AuthResult.Successful, JSON.parse(await resp.text()).data.actor]
|
return [APIResult.Successful, JSON.parse(await resp.text()).data.actor]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function authSession(email: string): Promise<[AuthResult, null | APIError]> {
|
export async function authSession(email: string): Promise<[APIResult, null | APIError]> {
|
||||||
logger.info('Sending new session authentication');
|
logger.info('Sending new session authentication');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -101,16 +101,16 @@ export async function authSession(email: string): Promise<[AuthResult, null | AP
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error sending authentication: ${rawerror.message}`);
|
logger.error(`error sending authentication: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
return [AuthResult.Successful, null]
|
return [APIResult.Successful, null]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function signup(email: string): Promise<[AuthResult, null | APIError]> {
|
export async function signup(email: string): Promise<[APIResult, null | APIError]> {
|
||||||
logger.info('sending signup');
|
logger.info('sending signup');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -127,16 +127,16 @@ export async function signup(email: string): Promise<[AuthResult, null | APIErro
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error sending authentication: ${rawerror.message}`);
|
logger.error(`error sending authentication: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
return [AuthResult.Successful, null]
|
return [APIResult.Successful, null]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function verifyLink(ml: string): Promise<[AuthResult, null | APIError]> {
|
export async function verifyLink(ml: string): Promise<[APIResult, null | APIError]> {
|
||||||
logger.info('checking magic link authentication');
|
logger.info('checking magic link authentication');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -153,15 +153,15 @@ export async function verifyLink(ml: string): Promise<[AuthResult, null | APIErr
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error sending authentication: ${rawerror.message}`);
|
logger.error(`error sending authentication: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
|
|
||||||
window.localStorage.setItem("session", JSON.parse(await resp.text()).data.sessionToken);
|
window.localStorage.setItem("session", JSON.parse(await resp.text()).data.sessionToken);
|
||||||
|
|
||||||
return [AuthResult.Successful, null]
|
return [APIResult.Successful, null]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ export interface TOTPCreateInfo {
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTotp(token: string): Promise<[AuthResult, TOTPCreateInfo | APIError]> {
|
export async function createTotp(token: string): Promise<[APIResult, TOTPCreateInfo | APIError]> {
|
||||||
logger.info('creating totp authenticator');
|
logger.info('creating totp authenticator');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -188,21 +188,21 @@ export async function createTotp(token: string): Promise<[AuthResult, TOTPCreate
|
||||||
logger.error('call returned error code');
|
logger.error('call returned error code');
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error sending totp create: ${rawerror.message}`);
|
logger.error(`error sending totp create: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
return [AuthResult.Successful, JSON.parse(await resp.text()).data]
|
return [APIResult.Successful, JSON.parse(await resp.text()).data]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function verifyTotp(token: string, totpToken: string, totpCode: string): Promise<[AuthResult, undefined | APIError]> {
|
export async function verifyTotp(token: string, totpToken: string, totpCode: string): Promise<[APIResult, undefined | APIError]> {
|
||||||
logger.info('verifying totp authenticator');
|
logger.info('verifying totp authenticator');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.debug(`api call: baseurl ${PUBLIC_BASE_URL}`);
|
logger.debug(`api call: baseurl ${PUBLIC_BASE_URL}`);
|
||||||
const resp = await fetch(`${PUBLIC_BASE_URL}/v1/totp-authenticators`, {
|
const resp = await fetch(`${PUBLIC_BASE_URL}/v1/verify-totp-authenticators`, {
|
||||||
'method': 'POST',
|
'method': 'POST',
|
||||||
'body': JSON.stringify({
|
'body': JSON.stringify({
|
||||||
totpToken: totpToken,
|
totpToken: totpToken,
|
||||||
|
@ -217,14 +217,45 @@ export async function verifyTotp(token: string, totpToken: string, totpCode: str
|
||||||
logger.error('call returned error code');
|
logger.error('call returned error code');
|
||||||
const rawerror = JSON.parse(await resp.text()).errors[0];
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
logger.error(`error sending totp create: ${rawerror.message}`);
|
logger.error(`error sending totp create: ${rawerror.message}`);
|
||||||
return [AuthResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
}
|
}
|
||||||
|
|
||||||
window.localStorage.setItem("mfa", JSON.parse(await resp.text()).data.authToken);
|
window.localStorage.setItem("mfa", JSON.parse(await resp.text()).data.authToken);
|
||||||
|
|
||||||
return [AuthResult.Successful, undefined]
|
return [APIResult.Successful, undefined]
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`error making API request: ${e}`);
|
logger.error(`error making API request: ${e}`);
|
||||||
return [AuthResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authTotp(token: string, totpCode: string): Promise<[APIResult, undefined | APIError]> {
|
||||||
|
logger.info('authorizing totp authenticator');
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug(`api call: baseurl ${PUBLIC_BASE_URL}`);
|
||||||
|
const resp = await fetch(`${PUBLIC_BASE_URL}/v1/auth/totp`, {
|
||||||
|
'method': 'POST',
|
||||||
|
'body': JSON.stringify({
|
||||||
|
code: `${totpCode}`
|
||||||
|
}),
|
||||||
|
'headers': {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!resp.ok) {
|
||||||
|
logger.error('call returned error code');
|
||||||
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
|
logger.error(`error sending totp create: ${rawerror.message}`);
|
||||||
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
|
}
|
||||||
|
|
||||||
|
window.localStorage.setItem("mfa", JSON.parse(await resp.text()).data.authToken);
|
||||||
|
|
||||||
|
return [APIResult.Successful, undefined]
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`error making API request: ${e}`);
|
||||||
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,50 @@
|
||||||
"label": "TOTP Code",
|
"label": "TOTP Code",
|
||||||
"button": "Verify"
|
"button": "Verify"
|
||||||
},
|
},
|
||||||
|
"networkcreate": {
|
||||||
|
"title": "Create your network",
|
||||||
|
"explain": "This defines what IP addresses will be assigned to your devices. The range you enter below must fall within either the RFC 1918 Private Address Space or the RFC 6598 Shared Address Space. Enter your network via CIDR notation.",
|
||||||
|
"label": "Network range",
|
||||||
|
"button": "Create network",
|
||||||
|
"valid": "Valid - {numIps} addresses from {start} to {end}",
|
||||||
|
"invalid": "Invalid",
|
||||||
|
"error": {
|
||||||
|
"generic": "Unable to create network: {err}",
|
||||||
|
"api": "Unable to contact the server. Try again later."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roles": {
|
||||||
|
"create": "Add",
|
||||||
|
"explain": "Roles control how hosts, lighthouses, and relays communicate through firewall rules.",
|
||||||
|
"noroles": "You don't have any roles. You'll need to add at least one before you can add any hosts.",
|
||||||
|
"add": {
|
||||||
|
"any": "Any",
|
||||||
|
"name": "Role name",
|
||||||
|
"desc": "Role description",
|
||||||
|
"button": "Create role",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"rules": "Inbound firewall rules",
|
||||||
|
"rulesexplainer": "Inbound traffic is denied by default. Add rules to allow traffic from hosts belonging to specific roles.",
|
||||||
|
"rulescols": {
|
||||||
|
"description": "Description",
|
||||||
|
"protocol": "Protocol",
|
||||||
|
"portrange": "Port range",
|
||||||
|
"allowedrole": "Allowed role"
|
||||||
|
},
|
||||||
|
"ruleremove": "Remove rule",
|
||||||
|
"ruleedit": "Edit rule",
|
||||||
|
"rulesadd": "Add rule",
|
||||||
|
"editrule": {
|
||||||
|
"protocol": "Protocol",
|
||||||
|
"range": "Port or port range",
|
||||||
|
"role": "Allowed role",
|
||||||
|
"desc": "Description",
|
||||||
|
"add": "Add rule",
|
||||||
|
"edit": "Edit rule",
|
||||||
|
"cancel": "Cancel"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"title": "{title} | Trifid Web UI",
|
"title": "{title} | Trifid Web UI",
|
||||||
"page": {
|
"page": {
|
||||||
|
@ -71,7 +115,10 @@
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"ml": "Verify Magic Link",
|
"ml": "Verify Magic Link",
|
||||||
"2fasetup": "Configure TOTP",
|
"2fasetup": "Configure TOTP",
|
||||||
"2fa": "2-Factor Authentication"
|
"2fa": "2-Factor Authentication",
|
||||||
|
"networkcreate": "Create Network",
|
||||||
|
"hosts": "Hosts",
|
||||||
|
"roles": "Roles"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import {APIResult} from "$lib/auth";
|
||||||
|
import type {APIError} from "$lib/auth";
|
||||||
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
|
||||||
|
logSetup();
|
||||||
|
const logger = new Logger("netcreate.ts");
|
||||||
|
|
||||||
|
export interface OrgCreateInfo {
|
||||||
|
organization: string,
|
||||||
|
ca: string,
|
||||||
|
network: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createNetwork(token: string, cidr: string): Promise<[APIResult, OrgCreateInfo | APIError]> {
|
||||||
|
logger.info('creating network');
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.debug(`api call: baseurl ${PUBLIC_BASE_URL}`);
|
||||||
|
const resp = await fetch(`${PUBLIC_BASE_URL}/v1/organization`, {
|
||||||
|
'method': 'POST',
|
||||||
|
'body': JSON.stringify({
|
||||||
|
cidr: `${cidr}`
|
||||||
|
}),
|
||||||
|
'headers': {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!resp.ok) {
|
||||||
|
logger.error('call returned error code');
|
||||||
|
const rawerror = JSON.parse(await resp.text()).errors[0];
|
||||||
|
logger.error(`error sending org create: ${rawerror.message}`);
|
||||||
|
return [APIResult.Failed, {code: rawerror.code, message: rawerror.message}];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [APIResult.Successful, await resp.json()]
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`error making API request: ${e}`);
|
||||||
|
return [APIResult.Failed, {code: "api_call_failed", message: `${e}`}]
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
import {isLoading, t} from "svelte-i18n";
|
import {isLoading, t} from "svelte-i18n";
|
||||||
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {AuthResult, authSession, isAuthedSession} from "$lib/auth.ts";
|
import {APIResult, authSession, authTotp, isAuthedSession, verifyTotp} from "$lib/auth.ts";
|
||||||
import type {SessionInfo} from "$lib/auth.ts";
|
import type {SessionInfo} from "$lib/auth.ts";
|
||||||
import type {APIError} from "$lib/auth.ts";
|
import type {APIError} from "$lib/auth.ts";
|
||||||
import {Logger, logSetup} from "$lib/logger";
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
let session_load_info = await isAuthedSession();
|
let session_load_info = await isAuthedSession();
|
||||||
if (session_load_info[0] == AuthResult.Failed) {
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
logger.error(`session load fail, the user is not already logged in`);
|
logger.error(`session load fail, the user is not already logged in`);
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
return;
|
return;
|
||||||
|
@ -39,6 +39,29 @@
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
|
let create_res = await authTotp(window.localStorage.getItem("session"), mfacode);
|
||||||
|
|
||||||
|
if (create_res[0] == APIResult.Failed) {
|
||||||
|
logger.error(`totp auth fail`);
|
||||||
|
isError = true;
|
||||||
|
let err = create_res[1] as APIError;
|
||||||
|
|
||||||
|
let etext = err.code;
|
||||||
|
|
||||||
|
if (etext === "api_call_failed") {
|
||||||
|
etext = $t('2fasetup.error.api');
|
||||||
|
} else if (etext === "ERR_USER_NO_TOTP") {
|
||||||
|
window.location.href = '/2fasetup';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = $t('2fasetup.error.generic', {values:{err:etext}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = '/admin';
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -52,7 +75,7 @@
|
||||||
<h3>{$t('2fa.subtitle')}</h3>
|
<h3>{$t('2fa.subtitle')}</h3>
|
||||||
<form on:submit|preventDefault={onSubmit}>
|
<form on:submit|preventDefault={onSubmit}>
|
||||||
<label for="mfacode">{$t('2fa.label')}</label>
|
<label for="mfacode">{$t('2fa.label')}</label>
|
||||||
<input type="number" bind:value={mfacode} id="mfacode"/>
|
<input type="text" bind:value={mfacode} id="mfacode"/>
|
||||||
<button>{$t('2fa.button')}</button>
|
<button>{$t('2fa.button')}</button>
|
||||||
{#if hasErrForm}
|
{#if hasErrForm}
|
||||||
<p>{errForm}</p>
|
<p>{errForm}</p>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import {isLoading, t} from "svelte-i18n";
|
import {isLoading, t} from "svelte-i18n";
|
||||||
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {AuthResult, authSession, createTotp, isAuthedSession, verifyTotp} from "$lib/auth.ts";
|
import {APIResult, authSession, createTotp, isAuthedSession, verifyTotp} from "$lib/auth.ts";
|
||||||
import type {TOTPCreateInfo} from "$lib/auth.ts";
|
import type {TOTPCreateInfo} from "$lib/auth.ts";
|
||||||
import type {SessionInfo} from "$lib/auth.ts";
|
import type {SessionInfo} from "$lib/auth.ts";
|
||||||
import type {APIError} from "$lib/auth.ts";
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
let session_load_info = await isAuthedSession();
|
let session_load_info = await isAuthedSession();
|
||||||
if (session_load_info[0] == AuthResult.Failed) {
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
logger.error(`session load fail, the user is not already logged in`);
|
logger.error(`session load fail, the user is not already logged in`);
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
return;
|
return;
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
let create_res = await createTotp(window.localStorage.getItem("session"));
|
let create_res = await createTotp(window.localStorage.getItem("session"));
|
||||||
|
|
||||||
if (create_res[0] == AuthResult.Failed) {
|
if (create_res[0] == APIResult.Failed) {
|
||||||
logger.error(`totp create fail`);
|
logger.error(`totp create fail`);
|
||||||
isError = true;
|
isError = true;
|
||||||
let err = create_res[1] as APIError;
|
let err = create_res[1] as APIError;
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
let create_res = await verifyTotp(window.localStorage.getItem("session"), totp_create_token, code);
|
let create_res = await verifyTotp(window.localStorage.getItem("session"), totp_create_token, code);
|
||||||
|
|
||||||
if (create_res[0] == AuthResult.Failed) {
|
if (create_res[0] == APIResult.Failed) {
|
||||||
logger.error(`totp auth fail`);
|
logger.error(`totp auth fail`);
|
||||||
isError = true;
|
isError = true;
|
||||||
let err = create_res[1] as APIError;
|
let err = create_res[1] as APIError;
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
<div><span>{totp_secret}</span></div>
|
<div><span>{totp_secret}</span></div>
|
||||||
<form on:submit|preventDefault={onSubmit}>
|
<form on:submit|preventDefault={onSubmit}>
|
||||||
<label for="code">{$t('2fasetup.verify')}</label>
|
<label for="code">{$t('2fasetup.verify')}</label>
|
||||||
<input bind:value={code} type="number" min="0" max="999999" id="code" />
|
<input bind:value={code} type="text" id="code" />
|
||||||
<button>{$t('2fasetup.button')}</button>
|
<button>{$t('2fasetup.button')}</button>
|
||||||
</form>
|
</form>
|
||||||
</LoadingWrapper>
|
</LoadingWrapper>
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
import {isLoading, t} from "svelte-i18n";
|
import {isLoading, t} from "svelte-i18n";
|
||||||
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {AuthResult, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
import {APIResult, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
||||||
import {Logger, logSetup} from "$lib/logger";
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
import type {APIError} from "$lib/auth.ts";
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
import {Configuration, NetworksApi} from "$lib/api";
|
||||||
|
|
||||||
let loading = true;
|
let loading = true;
|
||||||
let isError = false;
|
let isError = false;
|
||||||
|
@ -16,7 +18,7 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
let session_load_info = await isAuthedSession();
|
let session_load_info = await isAuthedSession();
|
||||||
if (session_load_info[0] == AuthResult.Failed) {
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
let err = session_load_info[1] as APIError;
|
let err = session_load_info[1] as APIError;
|
||||||
logger.error(`session load failed: ${err.code} ${err.message}`);
|
logger.error(`session load failed: ${err.code} ${err.message}`);
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
|
@ -24,13 +26,43 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let mfa_load_info = await isAuthedMFA();
|
let mfa_load_info = await isAuthedMFA();
|
||||||
if (mfa_load_info[0] == AuthResult.Failed) {
|
if (mfa_load_info[0] == APIResult.Failed) {
|
||||||
let err = mfa_load_info[1] as APIError;
|
let err = mfa_load_info[1] as APIError;
|
||||||
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
||||||
window.location.href = '/2fa';
|
window.location.href = '/2fa';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pull networks
|
||||||
|
const confgiuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
const networksApi = new NetworksApi(confgiuration);
|
||||||
|
let networks;
|
||||||
|
try {
|
||||||
|
networks = await networksApi.networksList();
|
||||||
|
} catch (e) {
|
||||||
|
let resp_json = await e.response.json();
|
||||||
|
if (resp_json.errors[0].code == "ERR_NO_ORG") {
|
||||||
|
window.location.href = "/networkcreate";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
isError = true;
|
||||||
|
error = $t("networkcreate.error.generic", {values:{err:resp_json.errors[0].code}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(networks);
|
||||||
|
|
||||||
|
if (networks.data?.length == 0) {
|
||||||
|
window.location.href = '/networkcreate';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = '/hosts';
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {isLoading, t} from "svelte-i18n";
|
||||||
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {APIResult, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
||||||
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
import {Configuration, NetworksApi} from "$lib/api";
|
||||||
|
import AdminBar from "$components/AdminBar.svelte";
|
||||||
|
|
||||||
|
let loading = true;
|
||||||
|
let isError = false;
|
||||||
|
let error = '';
|
||||||
|
$: currentlyLoading = $isLoading || loading;
|
||||||
|
|
||||||
|
logSetup();
|
||||||
|
let logger = new Logger("hosts/+page.svelte");
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let session_load_info = await isAuthedSession();
|
||||||
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = session_load_info[1] as APIError;
|
||||||
|
logger.error(`session load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/login';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mfa_load_info = await isAuthedMFA();
|
||||||
|
if (mfa_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = mfa_load_info[1] as APIError;
|
||||||
|
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/2fa';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull networks
|
||||||
|
const configuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
|
||||||
|
const networksApi = new NetworksApi(configuration);
|
||||||
|
let networks;
|
||||||
|
try {
|
||||||
|
networks = await networksApi.networksList();
|
||||||
|
} catch (e) {
|
||||||
|
let resp_json = await e.response.json();
|
||||||
|
if (resp_json.errors[0].code == "ERR_NO_ORG") {
|
||||||
|
window.location.href = "/networkcreate";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
isError = true;
|
||||||
|
error = $t("networkcreate.error.generic", {values:{err:resp_json.errors[0].code}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(networks);
|
||||||
|
|
||||||
|
if (networks.data?.length == 0) {
|
||||||
|
window.location.href = '/networkcreate';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{$t("common.title", {values: {title: $t("common.page.hosts")}})}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
|
||||||
|
<AdminBar selected="hosts" />
|
||||||
|
<h1>its not loading anymore</h1>
|
||||||
|
</LoadingWrapper>
|
|
@ -2,7 +2,7 @@
|
||||||
import {isLoading, t} from "svelte-i18n";
|
import {isLoading, t} from "svelte-i18n";
|
||||||
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {AuthResult, authSession, isAuthedSession} from "$lib/auth.ts";
|
import {APIResult, authSession, isAuthedSession} from "$lib/auth.ts";
|
||||||
import type {APIError} from "$lib/auth.ts";
|
import type {APIError} from "$lib/auth.ts";
|
||||||
import {Logger, logSetup} from "$lib/logger";
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
let session_load_info = await isAuthedSession();
|
let session_load_info = await isAuthedSession();
|
||||||
if (session_load_info[0] != AuthResult.Failed) {
|
if (session_load_info[0] != APIResult.Failed) {
|
||||||
logger.error(`session load success, the user is already logged in`);
|
logger.error(`session load success, the user is already logged in`);
|
||||||
window.location.href = '/2fa';
|
window.location.href = '/2fa';
|
||||||
return;
|
return;
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
let auth_result = await authSession(email);
|
let auth_result = await authSession(email);
|
||||||
|
|
||||||
if (auth_result[0] === AuthResult.Failed) {
|
if (auth_result[0] === APIResult.Failed) {
|
||||||
|
|
||||||
hasErrForm = true;
|
hasErrForm = true;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import {isLoading, t} from "svelte-i18n";
|
import {isLoading, t} from "svelte-i18n";
|
||||||
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {AuthResult, verifyLink} from "$lib/auth.ts";
|
import {APIResult, verifyLink} from "$lib/auth.ts";
|
||||||
import type {APIError} from "$lib/auth.ts";
|
import type {APIError} from "$lib/auth.ts";
|
||||||
import {Logger, logSetup} from "$lib/logger";
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
let call_result = await verifyLink(url.get("magicLinkToken"));
|
let call_result = await verifyLink(url.get("magicLinkToken"));
|
||||||
|
|
||||||
if (call_result[0] !== AuthResult.Successful) {
|
if (call_result[0] !== APIResult.Successful) {
|
||||||
let err = (call_result[1] as APIError).code;
|
let err = (call_result[1] as APIError).code;
|
||||||
|
|
||||||
if (err === "ERR_UNAUTHORIZED" || err === "ERR_EXPIRED") {
|
if (err === "ERR_UNAUTHORIZED" || err === "ERR_EXPIRED") {
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {isLoading, number, t} from "svelte-i18n";
|
||||||
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {APIResult, authTotp, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
||||||
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
import {Configuration, NetworksApi, ResponseError} from "$lib/api";
|
||||||
|
import {createNetwork} from "$lib/netcreate";
|
||||||
|
|
||||||
|
let loading = true;
|
||||||
|
let isError = false;
|
||||||
|
let error = '';
|
||||||
|
$: currentlyLoading = $isLoading || loading;
|
||||||
|
|
||||||
|
logSetup();
|
||||||
|
let logger = new Logger("networkcreate/+page.svelte");
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let session_load_info = await isAuthedSession();
|
||||||
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = session_load_info[1] as APIError;
|
||||||
|
logger.error(`session load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/login';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mfa_load_info = await isAuthedMFA();
|
||||||
|
if (mfa_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = mfa_load_info[1] as APIError;
|
||||||
|
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/2fa';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull networks
|
||||||
|
const confgiuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
const networksApi = new NetworksApi(confgiuration);
|
||||||
|
let networks;
|
||||||
|
try {
|
||||||
|
networks = await networksApi.networksList();
|
||||||
|
} catch (e) {
|
||||||
|
let resp_json = await e.response.json();
|
||||||
|
if (resp_json.errors[0].code != "ERR_NO_ORG") {
|
||||||
|
isError = true;
|
||||||
|
error = $t("networkcreate.error.generic", {values:{err:resp_json.errors[0].code}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (networks !== undefined && networks.data?.length != 0) {
|
||||||
|
window.location.href = '/admin';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
let cidr = "100.100.0.0/22";
|
||||||
|
let sub = $t("networkcreate.valid", {values:{numIps:$number(1024), start: "100.64.0.0", end: "100.127.255.255"}})
|
||||||
|
|
||||||
|
const regex = new RegExp(/^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/im);
|
||||||
|
|
||||||
|
function recalculateSub() {
|
||||||
|
// step 01: is it a valid CIDR?
|
||||||
|
logger.info(cidr);
|
||||||
|
if (!regex.test(cidr)) {
|
||||||
|
sub = $t("networkcreate.invalid");
|
||||||
|
logger.info("error: regex");
|
||||||
|
console.log(regex.exec(cidr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!cidr.includes("/")) {
|
||||||
|
sub = $t("networkcreate.invalid");
|
||||||
|
logger.info("error: noslash");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 02: is it in the local networks range?
|
||||||
|
// 192.168.*
|
||||||
|
// 10.*
|
||||||
|
// 172.16.*-172.31.*
|
||||||
|
// 100.64.*-100.127.*
|
||||||
|
function isInPrivateRange(addr: number, mask: number): boolean {
|
||||||
|
const netaddr_10 = 0b00001010_00000000_00000000_00000000;
|
||||||
|
const mask_8 = 0b11111111_00000000_00000000_00000000;
|
||||||
|
|
||||||
|
|
||||||
|
if (addr == netaddr_10 && mask == 8) return true;
|
||||||
|
|
||||||
|
const netaddr_172_16 = 0b10101100_00010000_00000000_00000000;
|
||||||
|
const mask_12 = 0b11111111_11110000_00000000_00000000;
|
||||||
|
|
||||||
|
if (addr == netaddr_172_16 && mask == 12) return true;
|
||||||
|
|
||||||
|
const netaddr_192_168 = 0b11000000_10101000_00000000_00000000;
|
||||||
|
const mask_16 = 0b11111111_11111111_00000000_00000000;
|
||||||
|
|
||||||
|
if (addr == netaddr_192_168 && mask == 16) return true;
|
||||||
|
|
||||||
|
const netaddr_10_64 = 0b01100100_01000000_00000000_00000000;
|
||||||
|
const mask_10 = 0b11111111_11000000_00000000_00000000;
|
||||||
|
|
||||||
|
if (addr == netaddr_10_64 && mask == 10) return true;
|
||||||
|
|
||||||
|
return (((addr & mask_8) == (netaddr_10 & mask_8) && mask > 8) || ((addr & mask_12) == (netaddr_172_16 & mask_12) && mask > 12) || ((addr & mask_16) == (netaddr_192_168 & mask_16) && mask > 16) || ((addr & mask_10) == (netaddr_10_64 & mask_10) && mask > 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
let [address, netmask] = cidr.split("/");
|
||||||
|
|
||||||
|
let address_octets = address.split(".");
|
||||||
|
let address_numerical = (parseInt(address_octets[0]) << 24 | parseInt(address_octets[1]) << 16 | parseInt(address_octets[2]) << 8 | parseInt(address_octets[3])) >>> 0;
|
||||||
|
|
||||||
|
if (!isInPrivateRange(address_numerical, parseInt(netmask))) {
|
||||||
|
sub = $t("networkcreate.invalid");
|
||||||
|
logger.info("not in private range");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 03: calculate address count
|
||||||
|
let prefix = parseInt(netmask);
|
||||||
|
let addressCount = Math.pow(2, 32 - prefix) - 2; // minus 2 for first and last addresses not usable
|
||||||
|
|
||||||
|
// step 04: calc addresses
|
||||||
|
|
||||||
|
let first_num = address_numerical;
|
||||||
|
let last_num = address_numerical + addressCount;
|
||||||
|
|
||||||
|
let first = [first_num >>> 24 & 0xFF, first_num >>> 16 & 0xFF, first_num >>> 8 & 0xFF, first_num & 0xFF].join(".");
|
||||||
|
let last = [last_num >>> 24 & 0xFF, last_num >>> 16 & 0xFF, last_num >>> 8 & 0xFF, last_num & 0xFF].join(".");
|
||||||
|
|
||||||
|
sub = $t("networkcreate.valid", {values:{numIps:$number(addressCount), start: first, end: last}})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onSubmit() {
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
let create_res = await createNetwork(window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa"), cidr);
|
||||||
|
|
||||||
|
if (create_res[0] == APIResult.Failed) {
|
||||||
|
logger.error(`totp auth fail`);
|
||||||
|
isError = true;
|
||||||
|
let err = create_res[1] as APIError;
|
||||||
|
|
||||||
|
let etext = err.code;
|
||||||
|
|
||||||
|
if (etext === "api_call_failed") {
|
||||||
|
etext = $t('networkcreate.error.api');
|
||||||
|
} else if (etext === "ERR_USER_NO_TOTP") {
|
||||||
|
window.location.href = '/2fasetup';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = $t('networkcreate.error.generic', {values:{err:etext}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.href = '/admin';
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{$t("common.title", {values: {title: $t("common.page.networkcreate")}})}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
|
||||||
|
<h1>{$t("networkcreate.title")}</h1>
|
||||||
|
<p>{$t("networkcreate.explain")}</p>
|
||||||
|
<form on:submit|preventDefault={onSubmit}>
|
||||||
|
<label for="cidr">{$t("networkcreate.label")}</label>
|
||||||
|
<input bind:value={cidr} on:input={recalculateSub} type="text" id="cidr" />
|
||||||
|
<button>{$t("networkcreate.button")}</button>
|
||||||
|
<span>{sub}</span>
|
||||||
|
</form>
|
||||||
|
</LoadingWrapper>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {isLoading, t} from "svelte-i18n";
|
||||||
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {APIResult, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
||||||
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
import {Configuration, NetworksApi, RolesApi} from "$lib/api";
|
||||||
|
import AdminBar from "$components/AdminBar.svelte";
|
||||||
|
|
||||||
|
let loading = true;
|
||||||
|
let isError = false;
|
||||||
|
let error = '';
|
||||||
|
$: currentlyLoading = $isLoading || loading;
|
||||||
|
|
||||||
|
logSetup();
|
||||||
|
let logger = new Logger("roles/+page.svelte");
|
||||||
|
|
||||||
|
let roles;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let session_load_info = await isAuthedSession();
|
||||||
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = session_load_info[1] as APIError;
|
||||||
|
logger.error(`session load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/login';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mfa_load_info = await isAuthedMFA();
|
||||||
|
if (mfa_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = mfa_load_info[1] as APIError;
|
||||||
|
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/2fa';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull networks
|
||||||
|
const configuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
|
||||||
|
const networksApi = new NetworksApi(configuration);
|
||||||
|
let networks;
|
||||||
|
try {
|
||||||
|
networks = await networksApi.networksList();
|
||||||
|
} catch (e) {
|
||||||
|
let resp_json = await e.response.json();
|
||||||
|
if (resp_json.errors[0].code == "ERR_NO_ORG") {
|
||||||
|
window.location.href = "/networkcreate";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
isError = true;
|
||||||
|
error = $t("networkcreate.error.generic", {values:{err:resp_json.errors[0].code}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(networks);
|
||||||
|
|
||||||
|
if (networks.data?.length == 0) {
|
||||||
|
window.location.href = '/networkcreate';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rolesApi = new RolesApi(configuration);
|
||||||
|
roles = await rolesApi.rolesList();
|
||||||
|
|
||||||
|
console.log(roles);
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
})
|
||||||
|
|
||||||
|
async function roleAdd() {
|
||||||
|
window.location.href = "/roles/add";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{$t("common.title", {values: {title: $t("common.page.roles")}})}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
|
||||||
|
<AdminBar selected="roles" />
|
||||||
|
|
||||||
|
<h1>{$t("common.page.roles")}</h1>
|
||||||
|
<button on:click={roleAdd}>{$t("roles.create")}</button>
|
||||||
|
|
||||||
|
<p>{$t("roles.explain")}</p>
|
||||||
|
|
||||||
|
{#if (roles.data.length === 0)}
|
||||||
|
<p>{$t("roles.noroles")}</p>
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
</LoadingWrapper>
|
|
@ -0,0 +1,296 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {isLoading, t} from "svelte-i18n";
|
||||||
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {APIResult, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
||||||
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
import {Configuration, NetworksApi, RolesApi} from "$lib/api";
|
||||||
|
import AdminBar from "$components/AdminBar.svelte";
|
||||||
|
|
||||||
|
let loading = true;
|
||||||
|
let isError = false;
|
||||||
|
let error = '';
|
||||||
|
$: currentlyLoading = $isLoading || loading;
|
||||||
|
|
||||||
|
logSetup();
|
||||||
|
let logger = new Logger("roles/add/+page.svelte");
|
||||||
|
|
||||||
|
let roles;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let session_load_info = await isAuthedSession();
|
||||||
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = session_load_info[1] as APIError;
|
||||||
|
logger.error(`session load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/login';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mfa_load_info = await isAuthedMFA();
|
||||||
|
if (mfa_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = mfa_load_info[1] as APIError;
|
||||||
|
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/2fa';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull networks
|
||||||
|
const configuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
|
||||||
|
const networksApi = new NetworksApi(configuration);
|
||||||
|
let networks;
|
||||||
|
try {
|
||||||
|
networks = await networksApi.networksList();
|
||||||
|
} catch (e) {
|
||||||
|
let resp_json = await e.response.json();
|
||||||
|
if (resp_json.errors[0].code == "ERR_NO_ORG") {
|
||||||
|
window.location.href = "/networkcreate";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
isError = true;
|
||||||
|
error = $t("networkcreate.error.generic", {values:{err:resp_json.errors[0].code}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(networks);
|
||||||
|
|
||||||
|
if (networks.data?.length == 0) {
|
||||||
|
window.location.href = '/networkcreate';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rolesApi = new RolesApi(configuration);
|
||||||
|
roles = await rolesApi.rolesList();
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
let roleName;
|
||||||
|
let roleDescription;
|
||||||
|
|
||||||
|
enum RuleProtocol {
|
||||||
|
ANY = 0,
|
||||||
|
TCP = 1,
|
||||||
|
UDP = 2,
|
||||||
|
ICMP = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
function protoToStringName(proto: RuleProtocol): string {
|
||||||
|
if (proto == RuleProtocol.ANY) {
|
||||||
|
return $t("roles.add.any");
|
||||||
|
} else if (proto == RuleProtocol.TCP) {
|
||||||
|
return "TCP";
|
||||||
|
} else if (proto == RuleProtocol.UDP) {
|
||||||
|
return "UDP";
|
||||||
|
} else if (proto == RuleProtocol.ICMP) {
|
||||||
|
return "ICMP";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Rule {
|
||||||
|
description: string,
|
||||||
|
protocol: RuleProtocol,
|
||||||
|
portRange: null | number | [number, number]
|
||||||
|
allowedRole: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
function prettyPortRange(range: null | number | [number, number]): string {
|
||||||
|
if (range === null) {
|
||||||
|
return $t("roles.add.any");
|
||||||
|
} else if (typeof range === 'number') {
|
||||||
|
return String(range);
|
||||||
|
} else {
|
||||||
|
return String(range[0]) + "-" + String(range[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findRole(role: string): string {
|
||||||
|
if (role === null) {
|
||||||
|
return $t("roles.add.any");
|
||||||
|
}
|
||||||
|
for (let i = 0; i < roles.data.length; i++) {
|
||||||
|
if (roles.data[i].id == role) {
|
||||||
|
return roles.data[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rules: Rule[] = [
|
||||||
|
{
|
||||||
|
description: "Allow pings from other hosts",
|
||||||
|
protocol: RuleProtocol.ICMP,
|
||||||
|
portRange: null,
|
||||||
|
allowedRole: null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function removeRule(rule: Rule) {
|
||||||
|
let newRules: Rule[] = [];
|
||||||
|
for (let i = 0; i < rules.length; i++) {
|
||||||
|
if (rules[i] != rule) {
|
||||||
|
newRules.push(rules[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rules = newRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isEditingRule = false;
|
||||||
|
let editingRuleDesc = "";
|
||||||
|
let editingRuleProtocol = RuleProtocol.ANY;
|
||||||
|
let editingRulePortRange = "any";
|
||||||
|
let editingRuleAllowedRole = "any";
|
||||||
|
let editingExistingRule = false;
|
||||||
|
let editingExistingTheRule = null;
|
||||||
|
|
||||||
|
$: allowClickingOtherStuff = isEditingRule;
|
||||||
|
|
||||||
|
function editRule(rule: Rule) {
|
||||||
|
if (isEditingRule) return;
|
||||||
|
|
||||||
|
isEditingRule = true;
|
||||||
|
editingRuleDesc = rule.description;
|
||||||
|
editingRuleProtocol = rule.protocol;
|
||||||
|
editingRulePortRange = prettyPortRange(rule.portRange);
|
||||||
|
editingRuleAllowedRole = (rule.allowedRole === null) ? "any" : rule.allowedRole;
|
||||||
|
editingExistingRule = true;
|
||||||
|
editingExistingTheRule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRule() {
|
||||||
|
if (isEditingRule) return;
|
||||||
|
isEditingRule = true;
|
||||||
|
editingRuleDesc = "";
|
||||||
|
editingRuleProtocol = RuleProtocol.ANY;
|
||||||
|
editingRulePortRange = "any";
|
||||||
|
editingRuleAllowedRole = "any";
|
||||||
|
editingExistingRule = false;
|
||||||
|
editingExistingTheRule = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishEdit() {
|
||||||
|
if (!isEditingRule) return;
|
||||||
|
|
||||||
|
// parse port range
|
||||||
|
let portRange;
|
||||||
|
if (editingRulePortRange == "any" || editingRulePortRange == "Any") {
|
||||||
|
portRange = null;
|
||||||
|
} else {
|
||||||
|
let split = editingRulePortRange.split("-");
|
||||||
|
if (split.length == 1) {
|
||||||
|
portRange = parseInt(split[0]);
|
||||||
|
} else {
|
||||||
|
portRange = [parseInt(split[0]), parseInt(split[1])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rules.push({
|
||||||
|
allowedRole: editingRuleAllowedRole,
|
||||||
|
description: editingRuleDesc,
|
||||||
|
portRange: portRange,
|
||||||
|
protocol: editingRuleProtocol
|
||||||
|
});
|
||||||
|
|
||||||
|
if (editingExistingRule) {
|
||||||
|
removeRule(editingExistingTheRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
isEditingRule = false;
|
||||||
|
editingRuleDesc = "";
|
||||||
|
editingRuleProtocol = RuleProtocol.ANY;
|
||||||
|
editingRulePortRange = "any";
|
||||||
|
editingRuleAllowedRole = "any";
|
||||||
|
editingExistingRule = false;
|
||||||
|
editingExistingTheRule = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelEdit() {
|
||||||
|
if (!isEditingRule) return;
|
||||||
|
isEditingRule = false;
|
||||||
|
editingRuleDesc = "";
|
||||||
|
editingRuleProtocol = RuleProtocol.ANY;
|
||||||
|
editingRulePortRange = "any";
|
||||||
|
editingRuleAllowedRole = "any";
|
||||||
|
editingExistingRule = false;
|
||||||
|
editingExistingTheRule = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function roleAdd() {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{$t("common.title", {values: {title: $t("common.page.roles")}})}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
|
||||||
|
<AdminBar selected="roles" />
|
||||||
|
|
||||||
|
<form on:submit|preventDefault={roleAdd}>
|
||||||
|
<label for="roleName">{$t("roles.add.name")}</label>
|
||||||
|
<input bind:value={roleName} type="text" id="roleName" />
|
||||||
|
<label for="roleDesc">{$t("roles.add.desc")}</label>
|
||||||
|
<input bind:value={roleDescription} type="text" id="roleDesc" />
|
||||||
|
<h3>{$t("roles.add.rules")}</h3>
|
||||||
|
<p>{$t("roles.add.rulesexplainer")}</p>
|
||||||
|
|
||||||
|
<!-- firewall rules -->
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{$t("roles.add.rulescols.description")}</th>
|
||||||
|
<th>{$t("roles.add.rulescols.protocol")}</th>
|
||||||
|
<th>{$t("roles.add.rulescols.portrange")}</th>
|
||||||
|
<th>{$t("roles.add.rulescols.allowedrole")}</th>
|
||||||
|
</tr>
|
||||||
|
{#each rules as rule}
|
||||||
|
<tr>
|
||||||
|
<td>{rule.description}</td>
|
||||||
|
<td>{protoToStringName(rule.protocol)}</td>
|
||||||
|
<td>{prettyPortRange(rule.portRange)}</td>
|
||||||
|
<td>{findRole(rule.allowedRole)}</td>
|
||||||
|
<button disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}>{$t("roles.add.ruleedit")}</button>
|
||||||
|
<button disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}>{$t("roles.add.ruleremove")}</button>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<button disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.add.rulesadd")}</button>
|
||||||
|
|
||||||
|
{#if isEditingRule}
|
||||||
|
<form on:submit|preventDefault>
|
||||||
|
<label for="ruleProtocol">{$t("roles.add.editrule.protocol")}</label>
|
||||||
|
<select id="ruleProtocol" bind:value="{editingRuleProtocol}">
|
||||||
|
<option value="{RuleProtocol.ANY}">{$t("roles.add.any")}</option>
|
||||||
|
<option value="{RuleProtocol.TCP}">TCP</option>
|
||||||
|
<option value="{RuleProtocol.UDP}">UDP</option>
|
||||||
|
<option value="{RuleProtocol.ICMP}">ICMP</option>
|
||||||
|
</select>
|
||||||
|
<label for="rulePortRange">{$t("roles.add.editrule.range")}</label>
|
||||||
|
<input type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
|
||||||
|
<label for="ruleAllowedRole">{$t("roles.add.editrule.role")}</label>
|
||||||
|
<select id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
|
||||||
|
<option value="any">{$t("roles.add.any")}</option>
|
||||||
|
{#each roles.data as role}
|
||||||
|
<option value="{role.id}">{role.name}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
<label for="ruleDescription">{$t("roles.add.editrule.desc")}</label>
|
||||||
|
<input type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
|
||||||
|
<button on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.add.editrule.edit") : $t("roles.add.editrule.add")}</button>
|
||||||
|
<button on:click|preventDefault={cancelEdit}>{$t("roles.add.editrule.cancel")}</button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<button disabled="{allowClickingOtherStuff}">{$t("roles.add.button")}</button>
|
||||||
|
<button disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.add.cancel")}</button>
|
||||||
|
</form>
|
||||||
|
</LoadingWrapper>
|
|
@ -2,7 +2,7 @@
|
||||||
import {isLoading, t} from "svelte-i18n";
|
import {isLoading, t} from "svelte-i18n";
|
||||||
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
import {onMount} from "svelte";
|
import {onMount} from "svelte";
|
||||||
import {AuthResult, authSession, isAuthedSession, signup} from "$lib/auth.ts";
|
import {APIResult, authSession, isAuthedSession, signup} from "$lib/auth.ts";
|
||||||
import type {APIError} from "$lib/auth.ts";
|
import type {APIError} from "$lib/auth.ts";
|
||||||
import {Logger, logSetup} from "$lib/logger";
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
let session_load_info = await isAuthedSession();
|
let session_load_info = await isAuthedSession();
|
||||||
if (session_load_info[0] != AuthResult.Failed) {
|
if (session_load_info[0] != APIResult.Failed) {
|
||||||
logger.error(`session load success, the user is already logged in`);
|
logger.error(`session load success, the user is already logged in`);
|
||||||
window.location.href = '/2fa';
|
window.location.href = '/2fa';
|
||||||
return;
|
return;
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
|
|
||||||
let auth_result = await signup(email);
|
let auth_result = await signup(email);
|
||||||
|
|
||||||
if (auth_result[0] === AuthResult.Failed) {
|
if (auth_result[0] === APIResult.Failed) {
|
||||||
|
|
||||||
hasErrForm = true;
|
hasErrForm = true;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ use trifid_pki::cert::{
|
||||||
pub struct CodegenRequiredInfo {
|
pub struct CodegenRequiredInfo {
|
||||||
pub host: host::Model,
|
pub host: host::Model,
|
||||||
pub host_static_addresses: HashMap<String, Vec<SocketAddrV4>>,
|
pub host_static_addresses: HashMap<String, Vec<SocketAddrV4>>,
|
||||||
pub host_config_overrides: Vec<host_config_override::Model>,
|
|
||||||
pub network: network::Model,
|
pub network: network::Model,
|
||||||
pub organization: organization::Model,
|
pub organization: organization::Model,
|
||||||
pub dh_pubkey: Vec<u8>,
|
pub dh_pubkey: Vec<u8>,
|
||||||
|
@ -40,6 +39,7 @@ pub struct CodegenRequiredInfo {
|
||||||
pub lighthouse_ips: Vec<Ipv4Addr>,
|
pub lighthouse_ips: Vec<Ipv4Addr>,
|
||||||
pub blocked_hosts: Vec<String>,
|
pub blocked_hosts: Vec<String>,
|
||||||
pub firewall_rules: Vec<NebulaConfigFirewallRule>,
|
pub firewall_rules: Vec<NebulaConfigFirewallRule>,
|
||||||
|
pub config_overrides: Vec<(String, String)>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn generate_config(
|
pub async fn generate_config(
|
||||||
|
@ -196,6 +196,28 @@ pub async fn generate_config(
|
||||||
local_range: None,
|
local_range: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Merge with config overrides and re-parse
|
||||||
|
let config_str = serde_yaml::to_string(&nebula_config)?;
|
||||||
|
let mut value: serde_yaml::Value = serde_yaml::from_str(&config_str)?;
|
||||||
|
|
||||||
|
for (key, kv_value) in &info.config_overrides {
|
||||||
|
// split up the key
|
||||||
|
// a.b.c.d = ['a']['b']['c']['d'] = value
|
||||||
|
let key_split = key.split('.');
|
||||||
|
|
||||||
|
let mut current_val = &mut value;
|
||||||
|
|
||||||
|
for key_iter in key_split {
|
||||||
|
current_val = current_val.get_mut(key_iter).ok_or("Invalid key-value override")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
*current_val = serde_yaml::from_str(kv_value)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let config_str_merged = serde_yaml::to_string(&value)?;
|
||||||
|
|
||||||
|
let nebula_config = serde_yaml::from_str(&config_str_merged)?;
|
||||||
|
|
||||||
Ok((nebula_config, cert))
|
Ok((nebula_config, cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,9 +337,15 @@ pub async fn collect_info<'a>(
|
||||||
|
|
||||||
let best_ca = best_ca.unwrap();
|
let best_ca = best_ca.unwrap();
|
||||||
|
|
||||||
|
// pull our host's config overrides
|
||||||
|
let config_overrides = host_config_overrides.iter().map(|u| {
|
||||||
|
(u.key.clone(), u.value.clone())
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
|
||||||
// pull our role's firewall rules
|
// pull our role's firewall rules
|
||||||
let firewall_rules = trifid_api_entities::entity::firewall_rule::Entity::find()
|
let firewall_rules = trifid_api_entities::entity::firewall_rule::Entity::find()
|
||||||
.filter(firewall_rule::Column::Role.eq(&host.id))
|
.filter(firewall_rule::Column::Role.eq(&host.role))
|
||||||
.all(&db.conn)
|
.all(&db.conn)
|
||||||
.await?;
|
.await?;
|
||||||
let firewall_rules = firewall_rules
|
let firewall_rules = firewall_rules
|
||||||
|
@ -349,7 +377,6 @@ pub async fn collect_info<'a>(
|
||||||
Ok(CodegenRequiredInfo {
|
Ok(CodegenRequiredInfo {
|
||||||
host,
|
host,
|
||||||
host_static_addresses: host_x_static_addresses,
|
host_static_addresses: host_x_static_addresses,
|
||||||
host_config_overrides,
|
|
||||||
network,
|
network,
|
||||||
organization: org,
|
organization: org,
|
||||||
dh_pubkey: dh_pubkey.to_vec(),
|
dh_pubkey: dh_pubkey.to_vec(),
|
||||||
|
@ -359,5 +386,6 @@ pub async fn collect_info<'a>(
|
||||||
lighthouse_ips: lighthouses,
|
lighthouse_ips: lighthouses,
|
||||||
blocked_hosts,
|
blocked_hosts,
|
||||||
firewall_rules,
|
firewall_rules,
|
||||||
|
config_overrides
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue