You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/oaer/lib/logic.ts

186 lines
4.3 KiB
TypeScript

/*
* logic.ts
* Copyright (C) 2024 veypi <i@veypi.com>
* 2024-10-24 16:36
* Distributed under terms of the GPL license.
*/
import bus from './bus'
import api, { apitoken } from './api'
4 weeks ago
import * as typs from './typs'
4 weeks ago
import { proxy } from './v2dom'
class Token {
iat?: string
iss?: string
jti?: string
exp?: number
aid?: string
icon?: string
name?: string
uid?: string
4 weeks ago
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)
4 weeks ago
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<Token>((resolve, reject) => {
if (!logic.token.refresh.isVaild() || this._typ === 'refresh') {
reject()
}
4 weeks ago
if (this.isVaild()) {
return resolve(this)
}
let aid = logic.oa_id
if (this._typ === 'app') {
aid = logic.app_id
}
4 weeks ago
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 => {
4 weeks ago
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: {
4 weeks ago
refresh: {} as Token,
oa: {} as Token,
app: {} as Token,
},
4 weeks ago
user: {} as typs.User,
myapps: [
{ name: 'a' },
{ name: 'b' },
],
ready: false,
4 weeks ago
getDetailUser() {
api.user.Get(logic.token.oa.uid!).then((u) => {
Object.assign(logic.user, u)
})
},
init: () => {
return new Promise<Token>((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) => {
4 weeks ago
apitoken.value = e.raw()
apitoken.set_updator(() => new Promise<string>((resolve, reject) => {
logic.token.oa.update().then(e => { resolve(e.raw()) }).catch(() => reject)
})
)
4 weeks ago
logic.getDetailUser()
if (logic.app_id !== logic.oa_id) {
logic.token.app.update().then((e) => {
logic.ready = true
resolve(e);
4 weeks ago
}).catch((e) => reject(e))
} else {
logic.ready = true
resolve(e);
}
4 weeks ago
}).catch((e) => {
reject(e)
})
} else {
reject()
}
}).catch(e => {
console.warn(`can not get info from ${logic.host}: ${e} `)
4 weeks ago
reject(e);
})
})
},
4 weeks ago
host: window.location.origin,
Host() {
4 weeks ago
return this.host
},
goto(url: string) {
if (url.startsWith('http')) {
window.location.href = url
return
}
if (!url.startsWith('/')) {
url = '/' + url
}
window.location.href = this.host + 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()
})
4 weeks ago
// load token from localStorage
logic.token.refresh = new Token('refresh')
3 weeks ago
logic.app_id = logic.token.refresh.aid || ''
4 weeks ago
logic.token.oa = new Token('oa')
logic.token.app = new Token('app')
export default logic