mirror of https://github.com/veypi/OneAuth.git
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.
214 lines
5.1 KiB
TypeScript
214 lines
5.1 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'
|
|
import * as typs from './typs'
|
|
import { proxy } from './v2dom'
|
|
|
|
class Token {
|
|
iat?: string
|
|
// oa_id
|
|
iss?: string
|
|
// token id
|
|
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<Token>((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(), 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()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
function objectToUrlParams(obj: { [key: string]: any }) {
|
|
return Object.keys(obj).map(key => {
|
|
return encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]);
|
|
}).join('&');
|
|
}
|
|
|
|
// 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<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) => {
|
|
apitoken.value = e.raw()
|
|
apitoken.set_updator(() => new Promise<string>((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, params?: { [key: string]: any }) {
|
|
let h = logic.host
|
|
if (params) {
|
|
if (url.includes('?')) {
|
|
url += '&' + objectToUrlParams(params)
|
|
} else {
|
|
url += '?' + objectToUrlParams(params)
|
|
}
|
|
}
|
|
if (!url) {
|
|
return ''
|
|
}
|
|
if (url.startsWith('http')) {
|
|
return url
|
|
}
|
|
if (!url.startsWith('/')) {
|
|
url = '/' + url
|
|
}
|
|
return h + url
|
|
},
|
|
goto(url: string, params?: { [key: string]: any }, newtab = false) {
|
|
if (newtab) {
|
|
window.open(logic.urlwarp(url, params), '_blank');
|
|
} else {
|
|
window.location.href = logic.urlwarp(url, params)
|
|
}
|
|
},
|
|
})
|
|
|
|
bus.on('login', () => {
|
|
logic.goto('/login', { redirect: window.location.href, uuid: logic.app_id })
|
|
})
|
|
bus.on('logout', () => {
|
|
apitoken.value = ''
|
|
if (logic.token.refresh.jti) {
|
|
api.token.Delete(logic.token.refresh.jti)
|
|
}
|
|
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
|