frequi_origin/src/shared/userService.ts
2022-12-10 13:08:47 +01:00

260 lines
7.1 KiB
TypeScript

import axios, { AxiosResponse } from 'axios';
import { AuthPayload, AuthResponse, BotDescriptors, AuthStorage, AuthStorageMulti } from '@/types';
const AUTH_LOGIN_INFO = 'ftAuthLoginInfo';
const APIBASE = '/api/v1';
export class UserService {
private botId: string;
constructor(botId: string) {
console.log('botId', botId);
this.botId = botId;
}
public renameBot(newName: string): void {
const newInfo = this.getLoginInfo();
newInfo.botName = newName;
this.storeLoginInfo(newInfo);
}
/**
* Stores info for current botId in the object of all bots.
*/
private storeLoginInfo(loginInfo: AuthStorage): void {
const allInfo = UserService.getAllLoginInfos();
allInfo[this.botId] = loginInfo;
localStorage.setItem(AUTH_LOGIN_INFO, JSON.stringify(allInfo));
}
/**
* Logout - removing info for this particular bot.
*/
private removeLoginInfo(): void {
const info = UserService.getAllLoginInfos();
delete info[this.botId];
localStorage.setItem(AUTH_LOGIN_INFO, JSON.stringify(info));
}
private setAccessToken(token: string): void {
const loginInfo = this.getLoginInfo();
loginInfo.accessToken = token;
this.storeLoginInfo(loginInfo);
}
/**
* Store autorefresh preference for this bot instance
* @param autoRefresh new autoRefresh value
*/
public setAutoRefresh(autoRefresh: boolean): void {
const loginInfo = this.getLoginInfo();
loginInfo.autoRefresh = autoRefresh;
this.storeLoginInfo(loginInfo);
}
/**
* Retrieve full logininfo object (for all registered bots)
* @returns
*/
private static getAllLoginInfos(): AuthStorageMulti {
const info = JSON.parse(localStorage.getItem(AUTH_LOGIN_INFO) || '{}');
return info;
}
/**
* Retrieve Login info object for the given bot
* @returns Login Info object
*/
public getLoginInfo(): AuthStorage {
const info = UserService.getAllLoginInfos();
if (this.botId in info && 'apiUrl' in info[this.botId] && 'refreshToken' in info[this.botId]) {
return info[this.botId];
}
return {
botName: '',
apiUrl: '',
username: '',
refreshToken: '',
accessToken: '',
autoRefresh: false,
};
}
setRefreshTokenExpired(): void {
const loginInfo = this.getLoginInfo();
loginInfo.refreshToken = '';
loginInfo.accessToken = '';
this.storeLoginInfo(loginInfo);
}
public static getAvailableBots(): BotDescriptors {
const allInfo = UserService.getAllLoginInfos();
const response: BotDescriptors = {};
Object.entries(allInfo).forEach(([k, v]) => {
response[k] = {
botId: k,
botName: v.botName,
botUrl: v.apiUrl,
};
});
return response;
}
public static getAvailableBotList(): string[] {
const allInfo = UserService.getAllLoginInfos();
return Object.keys(allInfo);
}
public getAutoRefresh(): boolean {
return this.getLoginInfo().autoRefresh;
}
public getAccessToken(): string {
return this.getLoginInfo().accessToken;
}
private getRefreshToken() {
return this.getLoginInfo().refreshToken;
}
public loggedIn() {
return this.getLoginInfo().refreshToken !== '';
}
private getAPIUrl(): string {
return this.getLoginInfo().apiUrl;
}
public logout(): void {
console.log('Logging out');
this.removeLoginInfo();
}
private async loginCall(auth: AuthPayload): Promise<AuthStorage> {
// Login using username / password
const { data } = await axios.post<{}, AxiosResponse<AuthResponse>>(
`${auth.url}/api/v1/token/login`,
{},
{
auth: { ...auth },
},
);
if (data.access_token && data.refresh_token) {
const obj: AuthStorage = {
botName: auth.botName,
apiUrl: auth.url,
username: auth.username,
accessToken: data.access_token || '',
refreshToken: data.refresh_token || '',
autoRefresh: true,
};
return Promise.resolve(obj);
}
return Promise.reject('login failed');
}
public async login(auth: AuthPayload) {
const obj = await this.loginCall(auth);
this.storeLoginInfo(obj);
}
public refreshToken(): Promise<string> {
console.log('Refreshing token...');
const token = this.getRefreshToken();
return new Promise((resolve, reject) => {
axios
.post<{}, AxiosResponse<AuthResponse>>(
`${this.getAPIUrl()}${APIBASE}/token/refresh`,
{},
{
headers: { Authorization: `Bearer ${token}` },
},
)
.then((response) => {
if (response.data.access_token) {
this.setAccessToken(response.data.access_token);
// Return plain access token
resolve(response.data.access_token);
}
})
.catch((err) => {
console.error(err);
if (err.response && err.response.status === 401) {
// Refresh token did not refresh.
console.log('Refresh token did not refresh.');
this.setRefreshTokenExpired();
} else if (err.response && (err.response.status === 500 || err.response.status === 404)) {
console.log('Bot seems to be offline... - retrying later');
}
reject(err);
});
});
}
public getBaseUrl(): string {
const baseURL = this.getAPIUrl();
if (baseURL === null) {
// Relative url
return APIBASE;
}
if (!baseURL.endsWith(APIBASE)) {
return `${baseURL}${APIBASE}`;
}
return `${baseURL}${APIBASE}`;
}
public getBaseWsUrl(): string {
const baseUrl = this.getBaseUrl();
if (baseUrl.startsWith('http://')) {
return baseUrl.replace('http://', 'ws://');
}
if (baseUrl.startsWith('https://')) {
return baseUrl.replace('https://', 'wss://');
}
return '';
}
/**
* Call on startup to migrate old login info to new login
*/
public static migrateLogin() {
// TODO: this is actually never called!
const AUTH_REFRESH_TOKEN = 'auth_ref_token'; // Legacy key - do not use
const AUTH_ACCESS_TOKEN = 'auth_access_token';
const AUTH_API_URL = 'auth_api_url';
const AUTO_REFRESH = 'ft_auto_refresh';
const apiUrl = JSON.parse(localStorage.getItem(AUTH_API_URL) || '{}');
const refreshToken = JSON.parse(localStorage.getItem(AUTH_REFRESH_TOKEN) || '{}');
const accessToken = JSON.parse(localStorage.getItem(AUTH_ACCESS_TOKEN) || '{}');
const autoRefresh: boolean = JSON.parse(localStorage.getItem(AUTO_REFRESH) || '{}');
if (
typeof apiUrl === 'string' &&
typeof refreshToken === 'string' &&
typeof accessToken === 'string'
) {
const loginInfo: AuthStorage = {
botName: '',
apiUrl,
refreshToken,
accessToken,
autoRefresh,
};
const x = new UserService('ftbot.0');
x.storeLoginInfo(loginInfo);
}
localStorage.removeItem(AUTH_REFRESH_TOKEN);
localStorage.removeItem(AUTH_ACCESS_TOKEN);
localStorage.removeItem(AUTH_API_URL);
localStorage.removeItem(AUTO_REFRESH);
}
}
export function useUserService(botId: string) {
const userservice = new UserService(botId);
return userservice;
}