/* * logic.ts * Copyright (C) 2024 veypi * 2024-10-24 16:36 * Distributed under terms of the GPL license. */ import bus from './bus' import api, { apitoken } from './api' import * as typs from './typs' import { proxy } from './v2dom' class Token { iat?: string iss?: string jti?: string exp?: number aid?: string icon?: string name?: string uid?: string access?: typs.Auths private _raw: string private _typ: 'refresh' | 'oa' | 'app' constructor(typ: 'refresh' | 'oa' | 'app') { this._typ = typ this._raw = localStorage.getItem(typ) || '' if (this._raw) { this.set(this._raw) } } isVaild() { if (this.exp) { const now = Math.floor(Date.now() / 1000); return now < this.exp } return false } set(t: string) { try { const parts = t.split('.'); // header = JSON.parse(atob(parts[0])); let body = JSON.parse(atob(parts[1])); // sign = parts[2] this._raw = t Object.assign(this, body) this.access = typs.NewAuths(body.access || []) localStorage.setItem(this._typ, t) } catch (error) { console.warn('Error parsing JWT:', error); } } clear() { localStorage.removeItem(this._typ) this.exp = undefined } raw() { return this._raw } update() { return new Promise((resolve, reject) => { if (!logic.token.refresh.isVaild() || this._typ === 'refresh') { reject() } if (this.isVaild()) { return resolve(this) } let aid = logic.oa_id if (this._typ === 'app') { aid = logic.app_id } api.token.Post({ refresh: logic.token.refresh.raw(), user_id: logic.token.refresh.uid!, app_id: aid }, { needRetry: false }).then(e => { if (this._typ === 'oa' && logic.app_id == logic.oa_id) { logic.token.app.set(e) } this.set(e) resolve(this) }).catch(e => { console.warn(`refresh token failed: ${e.err || e} `) bus.emit('logout') reject() }) }) } } // interface Token { // aid: string // exp: number // iat: string // icon: string // iss: string // jti: string // name: string // uid: string // isVaild: () => boolean // row: () => string // } const logic = proxy.Watch({ oa_id: '', app_id: '', token: { refresh: {} as Token, oa: {} as Token, app: {} as Token, }, user: {} as typs.User, myapps: [ { name: 'a' }, { name: 'b' }, ], ready: false, getDetailUser() { api.user.Get(logic.token.oa.uid!).then((u) => { Object.assign(logic.user, u) }) }, init: () => { return new Promise((resolve, reject) => { api.info().then(e => { logic.oa_id = e.id if (logic.token.refresh.isVaild()) { logic.app_id = logic.token.refresh.aid! logic.token.oa.update().then((e) => { apitoken.value = e.raw() apitoken.set_updator(() => new Promise((resolve, reject) => { logic.token.oa.update().then(e => { resolve(e.raw()) }).catch(() => reject) }) ) logic.getDetailUser() if (logic.app_id !== logic.oa_id) { logic.token.app.update().then((e) => { logic.ready = true resolve(e); }).catch((e) => reject(e)) } else { logic.ready = true resolve(e); } }).catch((e) => { reject(e) }) } else { reject() } }).catch(e => { console.warn(`can not get info from ${logic.host}: ${e} `) reject(e); }) }) }, host: window.location.origin, Host() { return logic.host }, urlwarp(url: string) { let h = logic.host if (!url) { return '' } if (url.startsWith('http')) { return url } if (!url.startsWith('/')) { url = '/' + url } return h + url }, goto(url: string) { window.location.href = logic.urlwarp(url) }, }) bus.on('login', () => { logic.goto('/login') }) bus.on('logout', () => { logic.ready = false logic.token.refresh.clear() logic.token.oa.clear() logic.token.app.clear() }) // load token from localStorage logic.token.refresh = new Token('refresh') logic.app_id = logic.token.refresh.aid || '' logic.token.oa = new Token('oa') logic.token.app = new Token('app') export default logic