mirror of
https://github.com/1f349/admin.1f349.com.git
synced 2024-11-09 22:32:57 +00:00
New OAuth based login system
This commit is contained in:
parent
11848b2d97
commit
f3d4b0e0a2
@ -1,4 +1,5 @@
|
|||||||
VITE_SSO_ORIGIN=http://localhost:9090
|
VITE_SSO_ORIGIN=http://localhost:9090
|
||||||
|
VITE_OAUTH2_CLIENT_ID=abc123
|
||||||
|
|
||||||
VITE_API_VIOLET=http://localhost:9095/v1/violet
|
VITE_API_VIOLET=http://localhost:9095/v1/violet
|
||||||
VITE_API_ORCHID=http://localhost:9095/v1/orchid
|
VITE_API_ORCHID=http://localhost:9095/v1/orchid
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
VITE_SSO_ORIGIN=https://sso.1f349.com
|
VITE_SSO_ORIGIN=https://sso.1f349.com
|
||||||
|
VITE_OAUTH2_CLIENT_ID=9b11a141-bcb8-4140-9c88-531a5d7bf15d
|
||||||
|
|
||||||
VITE_API_VIOLET=https://api.1f349.com/v1/violet
|
VITE_API_VIOLET=https://api.1f349.com/v1/violet
|
||||||
VITE_API_ORCHID=https://api.1f349.com/v1/orchid
|
VITE_API_ORCHID=https://api.1f349.com/v1/orchid
|
||||||
|
@ -6,9 +6,8 @@
|
|||||||
import CertificatesView from "./views/CertificatesView.svelte";
|
import CertificatesView from "./views/CertificatesView.svelte";
|
||||||
import SitesView from "./views/SitesView.svelte";
|
import SitesView from "./views/SitesView.svelte";
|
||||||
import {loginStore, parseJwt, type LoginStore} from "./stores/login";
|
import {loginStore, parseJwt, type LoginStore} from "./stores/login";
|
||||||
import {openLoginPopup} from "./utils/login-popup";
|
|
||||||
import {domainOption} from "./stores/domain-option";
|
import {domainOption} from "./stores/domain-option";
|
||||||
import {apiVerify} from "./utils/api-request";
|
import {LOGIN} from "./utils/login";
|
||||||
|
|
||||||
let sidebarOptions: Array<{name: string; view: typeof SvelteComponent<{}>}> = [
|
let sidebarOptions: Array<{name: string; view: typeof SvelteComponent<{}>}> = [
|
||||||
{name: "General", view: GeneralView},
|
{name: "General", view: GeneralView},
|
||||||
@ -34,7 +33,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
apiVerify().catch(() => {});
|
LOGIN.init();
|
||||||
|
LOGIN.userinfo(false);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -48,7 +48,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if $loginStore == null}
|
{#if $loginStore == null}
|
||||||
<div class="login-view">
|
<div class="login-view">
|
||||||
<button on:click={() => openLoginPopup()}>Login</button>
|
<button on:click={() => LOGIN.userinfo(true)}>Login</button>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="user-view">
|
<div class="user-view">
|
||||||
@ -58,6 +58,7 @@
|
|||||||
on:click={() => {
|
on:click={() => {
|
||||||
$loginStore = null;
|
$loginStore = null;
|
||||||
localStorage.removeItem("login-session");
|
localStorage.removeItem("login-session");
|
||||||
|
localStorage.removeItem("pop2_access_token");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Logout
|
Logout
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
import {get} from "svelte/store";
|
|
||||||
import {getBearer, loginStore} from "../stores/login";
|
|
||||||
|
|
||||||
const TOKEN_VERIFY_API = import.meta.env.VITE_SSO_ORIGIN + "/verify";
|
|
||||||
const TOKEN_REFRESH_API = import.meta.env.VITE_SSO_ORIGIN + "/refresh";
|
|
||||||
|
|
||||||
export async function apiRequest(url: string, init?: RequestInit): Promise<Response> {
|
|
||||||
// setup authorization header
|
|
||||||
if (init == undefined) init = {};
|
|
||||||
init.headers = {...init.headers, Authorization: getBearer()};
|
|
||||||
|
|
||||||
let f = await fetch(url, init);
|
|
||||||
if (f.status !== 403) return f;
|
|
||||||
|
|
||||||
let refreshResp = await fetch(TOKEN_REFRESH_API, {
|
|
||||||
method: "POST",
|
|
||||||
mode: "cors",
|
|
||||||
cache: "no-cache",
|
|
||||||
credentials: "include",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({token: get(loginStore)?.tokens.refresh}),
|
|
||||||
});
|
|
||||||
if (refreshResp.status !== 200) {
|
|
||||||
loginStore.set(null);
|
|
||||||
alert("Failed to refresh login session: please login again to continue");
|
|
||||||
throw new Error("403 Unauthorized");
|
|
||||||
}
|
|
||||||
let refreshJson = await refreshResp.json();
|
|
||||||
loginStore.set(refreshJson);
|
|
||||||
|
|
||||||
// update current authorization header
|
|
||||||
init.headers = {...init.headers, Authorization: getBearer()};
|
|
||||||
return await fetch(url, init);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function apiVerify() {
|
|
||||||
return await apiRequest(TOKEN_VERIFY_API, {
|
|
||||||
method: "POST",
|
|
||||||
mode: "cors",
|
|
||||||
cache: "no-cache",
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
import {loginStore} from "../stores/login";
|
|
||||||
|
|
||||||
let currentLoginPopup: {close: () => void} | null = null;
|
|
||||||
|
|
||||||
const ssoOrigin = import.meta.env.VITE_SSO_ORIGIN;
|
|
||||||
|
|
||||||
window.addEventListener("message", function (event) {
|
|
||||||
if (event.origin !== ssoOrigin) return;
|
|
||||||
if (isObject(event.data)) {
|
|
||||||
loginStore.set(event.data);
|
|
||||||
if (currentLoginPopup) currentLoginPopup.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
alert("Failed to log user in: the login data was probably corrupted");
|
|
||||||
});
|
|
||||||
|
|
||||||
function isObject(obj: Object) {
|
|
||||||
return obj != null && obj.constructor.name === "Object";
|
|
||||||
}
|
|
||||||
|
|
||||||
function popupCenterScreen(url: string, title: string, w: number, h: number, focus: boolean) {
|
|
||||||
const top = (screen.availHeight - h) / 4,
|
|
||||||
left = (screen.availWidth - w) / 2;
|
|
||||||
const popup = openWindow(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`);
|
|
||||||
if (focus === true && window.focus !== undefined && popup !== null) popup.focus();
|
|
||||||
return popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openWindow(url: string | URL, winnm: string, options: string): Window | null {
|
|
||||||
var wTop = firstAvailableValue([window.screen.availTop, window.screenY, window.screenTop, 0]);
|
|
||||||
var wLeft = firstAvailableValue([window.screen.availLeft, window.screenX, window.screenLeft, 0]);
|
|
||||||
let w: Window | null;
|
|
||||||
var top = 0,
|
|
||||||
left = 0;
|
|
||||||
var result;
|
|
||||||
if ((result = /top=(\d+)/g.exec(options))) top = parseInt(result[1]);
|
|
||||||
if ((result = /left=(\d+)/g.exec(options))) left = parseInt(result[1]);
|
|
||||||
if (options) {
|
|
||||||
options = options.replace("top=" + top, "top=" + (top + wTop));
|
|
||||||
options = options.replace("left=" + left, "left=" + (left + wLeft));
|
|
||||||
w = window.open(url, winnm, options);
|
|
||||||
} else w = window.open(url, winnm);
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
function firstAvailableValue(arr: any) {
|
|
||||||
for (var i = 0; i < arr.length; i++) if (typeof arr[i] != "undefined") return arr[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function openLoginPopup() {
|
|
||||||
if (currentLoginPopup) currentLoginPopup.close();
|
|
||||||
currentLoginPopup = popupCenterScreen(ssoOrigin + "/popup?origin=" + encodeURIComponent(location.origin), "Login with 1f349 SSO", 500, 500, false);
|
|
||||||
}
|
|
33
src/utils/login.ts
Normal file
33
src/utils/login.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import {get} from "svelte/store";
|
||||||
|
import {getBearer, loginStore} from "../stores/login";
|
||||||
|
import {POP2} from "./pop2";
|
||||||
|
|
||||||
|
const TOKEN_AUTHORIZE_API = import.meta.env.VITE_SSO_ORIGIN + "/authorize";
|
||||||
|
const TOKEN_USERINFO_API = import.meta.env.VITE_SSO_ORIGIN + "/userinfo";
|
||||||
|
const OAUTH2_CLIENT_ID = import.meta.env.VITE_OAUTH2_CLIENT_ID;
|
||||||
|
|
||||||
|
export const LOGIN = {
|
||||||
|
init: () => {
|
||||||
|
POP2.init(TOKEN_AUTHORIZE_API, OAUTH2_CLIENT_ID, "openid profile name", 500, 600);
|
||||||
|
},
|
||||||
|
clientRequest: (resource: string, options: RequestInit, refresh: boolean) => {
|
||||||
|
return POP2.clientRequest(resource, options, refresh);
|
||||||
|
},
|
||||||
|
userinfo: (popup: boolean) => {
|
||||||
|
console.info("userinfo", popup);
|
||||||
|
POP2.getToken((token: string) => {
|
||||||
|
POP2.clientRequest(TOKEN_USERINFO_API, {}, popup)
|
||||||
|
.then(x => x.json())
|
||||||
|
.then(x => {
|
||||||
|
console.log(token, x);
|
||||||
|
loginStore.set({
|
||||||
|
userinfo: x,
|
||||||
|
tokens: {access: token, refresh: ""},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(x => {
|
||||||
|
console.error(x);
|
||||||
|
});
|
||||||
|
}, popup);
|
||||||
|
},
|
||||||
|
};
|
187
src/utils/pop2.js
Normal file
187
src/utils/pop2.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/* Simple OAuth 2.0 Client flow library
|
||||||
|
|
||||||
|
Author: MrMelon54, timdream
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
POP2.init(client_id, scope)
|
||||||
|
Initialize the library.
|
||||||
|
redirect_uri is the current page (window.location.href).
|
||||||
|
This function should be put before Analytics so that the second click won't result a page view register.
|
||||||
|
POP2.getToken(callback)
|
||||||
|
Send access token to the callback function as the first argument.
|
||||||
|
If not logged in this triggers login popup and execute login after logged in.
|
||||||
|
Be sure to call this function in user-triggered event (such as click) to prevent popup blocker.
|
||||||
|
If not sure do use isLoggedIn() below to check first.
|
||||||
|
POP2.isLoggedIn()
|
||||||
|
boolean
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
export const POP2 = (function (w) {
|
||||||
|
const windowName = "pop2_oauth2_login_popup";
|
||||||
|
|
||||||
|
if (window.name === windowName) {
|
||||||
|
if (window.opener && window.opener.POP2) {
|
||||||
|
if (window.location.hash.indexOf("access_token") !== -1) {
|
||||||
|
window.opener.POP2.receiveToken(
|
||||||
|
window.location.hash.replace(/^.*access_token=([^&]+).*$/, "$1"),
|
||||||
|
parseInt(window.location.hash.replace(/^.*expires_in=([^&]+).*$/, "$1")),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (window.location.search.indexOf("error=")) {
|
||||||
|
window.opener.POP2.receiveToken("ERROR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function popupCenterScreen(url, title, w, h) {
|
||||||
|
const top = (screen.availHeight - h) / 4,
|
||||||
|
left = (screen.availWidth - w) / 2;
|
||||||
|
return openWindow(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openWindow(url, winnm, options) {
|
||||||
|
const wTop = firstAvailableValue([window.screen.availTop, window.screenY, window.screenTop, 0]);
|
||||||
|
const wLeft = firstAvailableValue([window.screen.availLeft, window.screenX, window.screenLeft, 0]);
|
||||||
|
let top = "0",
|
||||||
|
left = "0",
|
||||||
|
result;
|
||||||
|
if ((result = /top=(\d+)/g.exec(options))) top = parseInt(result[1]);
|
||||||
|
if ((result = /left=(\d+)/g.exec(options))) left = parseInt(result[1]);
|
||||||
|
let w;
|
||||||
|
if (options) {
|
||||||
|
options = options.replace("top=" + top, "top=" + (parseInt(top) + wTop));
|
||||||
|
options = options.replace("left=" + left, "left=" + (parseInt(left) + wLeft));
|
||||||
|
w = window.open(url, winnm, options);
|
||||||
|
} else w = window.open(url, winnm);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstAvailableValue(arr) {
|
||||||
|
for (let i = 0; i < arr.length; i++) if (typeof arr[i] != "undefined") return arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
let client_endpoint,
|
||||||
|
client_id,
|
||||||
|
scope = "",
|
||||||
|
redirect_uri = window.location.href.substr(0, window.location.href.length - window.location.hash.length).replace(/#$/, ""),
|
||||||
|
access_token = localStorage.getItem("pop2_access_token"),
|
||||||
|
callbackWaitForToken,
|
||||||
|
w_width = 400,
|
||||||
|
w_height = 360;
|
||||||
|
|
||||||
|
const POP2 = {
|
||||||
|
// init
|
||||||
|
init: function (f_client_endpoint, f_client_id, f_scope, width, height) {
|
||||||
|
if (!f_client_endpoint) return false;
|
||||||
|
if (!f_client_id) return false;
|
||||||
|
client_endpoint = f_client_endpoint;
|
||||||
|
client_id = f_client_id;
|
||||||
|
if (f_scope) scope = f_scope;
|
||||||
|
if (width) w_width = width;
|
||||||
|
if (height) w_height = height;
|
||||||
|
},
|
||||||
|
// receive token from popup
|
||||||
|
receiveToken: function (token, expires_in) {
|
||||||
|
if (token !== "ERROR") {
|
||||||
|
access_token = token;
|
||||||
|
localStorage.setItem("pop2_access_token", access_token);
|
||||||
|
if (callbackWaitForToken) callbackWaitForToken(access_token);
|
||||||
|
setTimeout(function () {
|
||||||
|
access_token = undefined;
|
||||||
|
localStorage.removeItem("pop2_access_token");
|
||||||
|
}, expires_in * 1000);
|
||||||
|
} else if (token === false) {
|
||||||
|
callbackWaitForToken = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// pass the access token to callback
|
||||||
|
// if not logged in this triggers login popup;
|
||||||
|
// use isLoggedIn to check login first to prevent popup blocker
|
||||||
|
getToken: function (callback, popup = true) {
|
||||||
|
if (!client_id || !redirect_uri || !scope) {
|
||||||
|
alert("You need init() first. Check the program flow.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!popup) throw Error("missing access token");
|
||||||
|
if (!access_token) {
|
||||||
|
callbackWaitForToken = callback;
|
||||||
|
popupCenterScreen(
|
||||||
|
client_endpoint +
|
||||||
|
"?response_type=token" +
|
||||||
|
"&redirect_uri=" +
|
||||||
|
encodeURIComponent(redirect_uri) +
|
||||||
|
"&scope=" +
|
||||||
|
encodeURIComponent(scope) +
|
||||||
|
"&client_id=" +
|
||||||
|
encodeURIComponent(client_id),
|
||||||
|
windowName,
|
||||||
|
w_width,
|
||||||
|
w_height,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
callback(access_token);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clientRequest: function (resource, options, refresh = false) {
|
||||||
|
const sendRequest = function () {
|
||||||
|
options.credentials = "include";
|
||||||
|
if (!options.headers) options.headers = {};
|
||||||
|
options.headers["Authorization"] = "Bearer " + access_token;
|
||||||
|
return new Promise(function (res, rej) {
|
||||||
|
fetch(resource, options)
|
||||||
|
.then(function (x) {
|
||||||
|
if (x.status >= 200 && x.status < 300) res(x);
|
||||||
|
else rej(x);
|
||||||
|
})
|
||||||
|
.catch(function (x) {
|
||||||
|
rej(["failed to send request", x]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const resendRequest = function () {
|
||||||
|
return new Promise(function (res, rej) {
|
||||||
|
access_token = undefined;
|
||||||
|
POP2.getToken(function () {
|
||||||
|
sendRequest()
|
||||||
|
.then(function (x) {
|
||||||
|
res(x);
|
||||||
|
})
|
||||||
|
.catch(function (x) {
|
||||||
|
rej(["failed to resend request", x]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!refresh) {
|
||||||
|
if (!access_token) return Promise.reject("missing access token");
|
||||||
|
return sendRequest();
|
||||||
|
} else {
|
||||||
|
return new Promise(function (res, rej) {
|
||||||
|
sendRequest()
|
||||||
|
.then(function (x) {
|
||||||
|
res(x);
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
resendRequest()
|
||||||
|
.then(function (x) {
|
||||||
|
res(x);
|
||||||
|
})
|
||||||
|
.catch(function (x) {
|
||||||
|
rej(x);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
window.POP2 = POP2;
|
||||||
|
return POP2;
|
||||||
|
})();
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {domainOption} from "../stores/domain-option";
|
import {domainOption} from "../stores/domain-option";
|
||||||
import {type Cert, certsTable} from "../stores/certs";
|
import {type Cert, certsTable} from "../stores/certs";
|
||||||
import {apiRequest} from "../utils/api-request";
|
import {LOGIN} from "../utils/login";
|
||||||
|
|
||||||
const apiOrchid = import.meta.env.VITE_API_ORCHID;
|
const apiOrchid = import.meta.env.VITE_API_ORCHID;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@
|
|||||||
let promiseForTable: Promise<void> = reloadTable();
|
let promiseForTable: Promise<void> = reloadTable();
|
||||||
|
|
||||||
async function reloadTable(): Promise<void> {
|
async function reloadTable(): Promise<void> {
|
||||||
let f = await apiRequest(apiOrchid + "/owned");
|
let f = await LOGIN.clientRequest(apiOrchid + "/owned", {}, false);
|
||||||
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
||||||
let fJson = await f.json();
|
let fJson = await f.json();
|
||||||
let rows = fJson as Map<number, Cert>;
|
let rows = fJson as Map<number, Cert>;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {domainOption} from "../stores/domain-option";
|
import {domainOption} from "../stores/domain-option";
|
||||||
import {type Site, sitesTable} from "../stores/sites";
|
import {type Site, sitesTable} from "../stores/sites";
|
||||||
import {apiRequest} from "../utils/api-request";
|
import {LOGIN} from "../utils/login";
|
||||||
|
|
||||||
const apiSiteHosting = import.meta.env.VITE_API_SITE_HOSTING;
|
const apiSiteHosting = import.meta.env.VITE_API_SITE_HOSTING;
|
||||||
|
|
||||||
@ -23,7 +23,7 @@
|
|||||||
let promiseForTable: Promise<void> = reloadTable();
|
let promiseForTable: Promise<void> = reloadTable();
|
||||||
|
|
||||||
async function reloadTable(): Promise<void> {
|
async function reloadTable(): Promise<void> {
|
||||||
let f = await apiRequest(apiSiteHosting);
|
let f = await LOGIN.clientRequest(apiSiteHosting, {}, false);
|
||||||
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
||||||
let fJson = await f.json();
|
let fJson = await f.json();
|
||||||
let rows = fJson as Site[];
|
let rows = fJson as Site[];
|
||||||
@ -33,19 +33,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteBranch(site: Site, branch: string) {
|
async function deleteBranch(site: Site, branch: string) {
|
||||||
let f = await apiRequest(apiSiteHosting, {
|
let f = await LOGIN.clientRequest(
|
||||||
|
apiSiteHosting,
|
||||||
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({submit: "delete-branch", site: site.domain, branch}),
|
body: JSON.stringify({submit: "delete-branch", site: site.domain, branch}),
|
||||||
});
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
||||||
promiseForTable = reloadTable();
|
promiseForTable = reloadTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resetSiteSecret(site: Site) {
|
async function resetSiteSecret(site: Site) {
|
||||||
let f = await apiRequest(apiSiteHosting, {
|
let f = await LOGIN.clientRequest(
|
||||||
|
apiSiteHosting,
|
||||||
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({submit: "secret", site: site.domain}),
|
body: JSON.stringify({submit: "secret", site: site.domain}),
|
||||||
});
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
||||||
let fJson = await f.json();
|
let fJson = await f.json();
|
||||||
alert("New secret: " + fJson.secret);
|
alert("New secret: " + fJson.secret);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {apiRequest} from "../utils/api-request";
|
import {LOGIN} from "../utils/login";
|
||||||
import {writable, type Writable} from "svelte/store";
|
import {writable, type Writable} from "svelte/store";
|
||||||
import type {CSPair} from "../types/cspair";
|
import type {CSPair} from "../types/cspair";
|
||||||
import {domainOption} from "../stores/domain-option";
|
import {domainOption} from "../stores/domain-option";
|
||||||
@ -42,7 +42,7 @@
|
|||||||
let promiseForTable: Promise<void> = reloadTable();
|
let promiseForTable: Promise<void> = reloadTable();
|
||||||
|
|
||||||
async function reloadTable(): Promise<void> {
|
async function reloadTable(): Promise<void> {
|
||||||
let f = await apiRequest(apiUrl);
|
let f = await LOGIN.clientRequest(apiUrl, {}, false);
|
||||||
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
if (f.status !== 200) throw new Error("Unexpected status code: " + f.status);
|
||||||
let fJson = await f.json();
|
let fJson = await f.json();
|
||||||
|
|
||||||
@ -77,10 +77,14 @@
|
|||||||
})
|
})
|
||||||
.sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0))
|
.sort((a, _) => (a.type === "del" ? -1 : a.type === "ins" ? 1 : 0))
|
||||||
.map(x => {
|
.map(x => {
|
||||||
x.v.p = apiRequest(apiUrl, {
|
x.v.p = LOGIN.clientRequest(
|
||||||
|
apiUrl,
|
||||||
|
{
|
||||||
method: x.type == "del" ? "DELETE" : "POST",
|
method: x.type == "del" ? "DELETE" : "POST",
|
||||||
body: JSON.stringify(x.type == "del" ? {src: (x.v.server as T).src} : x.v.client),
|
body: JSON.stringify(x.type == "del" ? {src: (x.v.server as T).src} : x.v.client),
|
||||||
}).then(x => {
|
},
|
||||||
|
false,
|
||||||
|
).then(x => {
|
||||||
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
|
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
|
||||||
});
|
});
|
||||||
return x.v.p;
|
return x.v.p;
|
||||||
|
Loading…
Reference in New Issue
Block a user