import { TokenClaims } from "@common/TokenClaims"; import * as jwt from "jsonwebtoken"; import { computed, createAtom, IAtom, observable } from "mobx"; export class Token { @observable token: string | null; @computed get claims(): TClaims | null { if (this.token == null) { return null; } return jwt.decode(this.token) as any; } private isExpiredAtom: IAtom; private currentTime!: number; private expirationTimer: number | undefined; constructor(token: string | null = null) { this.token = token; this.isExpiredAtom = createAtom( "Token.isExpired", this.startUpdating, this.stopUpdating ); this.updateCurrentTime(); } toJSON() { return this.token; } updateCurrentTime = (reportChanged: boolean = true) => { if (reportChanged) { this.isExpiredAtom.reportChanged(); } this.currentTime = Date.now() / 1000; }; get remainingTime(): number { if (!this.isExpiredAtom.reportObserved()) { this.updateCurrentTime(false); } if (this.claims == null || this.claims.exp == null) { return Number.NEGATIVE_INFINITY; } return this.claims.exp - this.currentTime; } private startUpdating = () => { this.stopUpdating(); const remaining = this.remainingTime; if (remaining > 0) { this.expirationTimer = setTimeout( this.updateCurrentTime, this.remainingTime ); } }; private stopUpdating = () => { if (this.expirationTimer != null) { clearTimeout(this.expirationTimer); this.expirationTimer = undefined; } }; get isExpired() { return this.remainingTime <= 0; } @computed get isValid() { return this.token != null && !this.isExpired; } }