// Copyright (C) 2023 Vaughn Nugent // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import { AxiosInstance } from "axios"; import { get } from "@vueuse/core"; import { computed } from "vue"; import { delay } from "lodash"; import { usePkiAuth, useSession, useUser } from "@vnuge/vnlib.browser"; import type { ClientStatus } from "./types"; import type { AppSettings } from "./settings"; import type { JsonObject } from "type-fest"; import { type FeatureApi, type BgRuntime, type IFeatureExport, exportForegroundApi, popupAndOptionsOnly, popupOnly } from "./framework"; import { waitForChangeFn } from "./util"; export interface ProectedHandler { (message: T): Promise } export interface MessageHandler { (message: T): Promise } export interface ApiMessageHandler { (message: T, apiHandle: { axios: AxiosInstance }): Promise } export interface UserApi extends FeatureApi { login: (token: string) => Promise logout: () => Promise getProfile: () => Promise getStatus: () => Promise waitForChange: () => Promise } export const useAuthApi = (): IFeatureExport => { return { background: ({ state }:BgRuntime): UserApi =>{ const { loggedIn, clearLoginState } = useSession(); const { currentConfig } = state const { logout, getProfile, heartbeat, userName } = useUser(); const currentPkiPath = computed(() => `${currentConfig.value.accountBasePath}/pki`) //Use pki login controls const { login } = usePkiAuth(currentPkiPath as any) //We can send post messages to the server heartbeat endpoint to get status const runHeartbeat = async () => { //Only run if the api thinks its logged in, and config is enabled if (!loggedIn.value || currentConfig.value.heartbeat !== true) { return } try { //Post against the heartbeat endpoint await heartbeat() } catch (error: any) { if (error.response?.status === 401 || error.response?.status === 403) { //If we get a 401, the user is no longer logged in clearLoginState() } } } //Configure interval to run every 5 minutes to update the status setInterval(runHeartbeat, 60 * 1000); delay(runHeartbeat, 1000) //Delay 1 second to allow the extension to load return { waitForChange: waitForChangeFn([currentConfig, loggedIn, userName]), login: popupOnly(async (token: string): Promise => { //Perform login await login(token) //load profile getProfile() return true; }), logout: popupOnly(async (): Promise => { //Perform logout await logout() //Cleanup after logout clearLoginState() }), getProfile: popupAndOptionsOnly(getProfile), async getStatus (){ return { //Logged in if the cookie is set and the api flag is set loggedIn: get(loggedIn), //username userName: get(userName), } as ClientStatus }, } }, foreground: exportForegroundApi([ 'login', 'logout', 'getProfile', 'getStatus', 'waitForChange' ]), } }