release: @marketplaces/auth 0.1.0 (built from main)
This commit is contained in:
120
dist/ed25519/session.service.js
vendored
Normal file
120
dist/ed25519/session.service.js
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
import { Injectable, computed, signal } from '@angular/core';
|
||||
import { JwtService } from './jwt.service';
|
||||
const TOKEN_STORAGE_KEY = 'ed25519AdminToken';
|
||||
const REFRESH_STORAGE_KEY = 'ed25519AdminRefreshToken';
|
||||
/** Refresh this long before actual expiry, so a request never races an expiring token. */
|
||||
const REFRESH_SKEW_MS = 60_000;
|
||||
/**
|
||||
* Holds the Ed25519-flow JWT/refresh-token pair and derived claims. Separate
|
||||
* from the telegram module's AdminAuthService (Telegram-session state) by
|
||||
* design - the two auth mechanisms are not merged until both ship on the
|
||||
* same backend and a migration decision is made.
|
||||
*/
|
||||
let SessionService = class SessionService {
|
||||
constructor() {
|
||||
this.jwt = new JwtService();
|
||||
this.tokenSignal = signal(null);
|
||||
this.refreshTokenSignal = signal(null);
|
||||
this.claimsSignal = signal(null);
|
||||
this.statusSignal = signal('unknown');
|
||||
this.token = this.tokenSignal.asReadonly();
|
||||
this.claims = this.claimsSignal.asReadonly();
|
||||
this.status = this.statusSignal.asReadonly();
|
||||
this.isAuthenticated = computed(() => this.statusSignal() === 'authenticated');
|
||||
this.role = computed(() => this.claimsSignal()?.role ?? null);
|
||||
}
|
||||
/** Called once by AuthService on init to wire up the refresh trigger without a circular DI dependency. */
|
||||
onRefreshDue(callback) {
|
||||
this.refreshCallback = callback;
|
||||
}
|
||||
/** Restores session state from persisted storage. Returns true if a (possibly expired) session was found. */
|
||||
restore() {
|
||||
this.statusSignal.set('restoring');
|
||||
const token = this.readStorage(TOKEN_STORAGE_KEY);
|
||||
const refreshToken = this.readStorage(REFRESH_STORAGE_KEY);
|
||||
if (!token || !refreshToken) {
|
||||
this.statusSignal.set('unauthenticated');
|
||||
return false;
|
||||
}
|
||||
const claims = this.jwt.decode(token);
|
||||
if (!claims) {
|
||||
this.clear();
|
||||
return false;
|
||||
}
|
||||
this.tokenSignal.set(token);
|
||||
this.refreshTokenSignal.set(refreshToken);
|
||||
this.claimsSignal.set(claims);
|
||||
if (this.jwt.isExpired(claims)) {
|
||||
this.statusSignal.set('expired');
|
||||
}
|
||||
else {
|
||||
this.statusSignal.set('authenticated');
|
||||
this.scheduleRefresh(claims);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
activate(tokens) {
|
||||
const claims = this.jwt.decode(tokens.token);
|
||||
if (!claims) {
|
||||
throw new Error('Received a malformed JWT from the auth backend.');
|
||||
}
|
||||
this.tokenSignal.set(tokens.token);
|
||||
this.refreshTokenSignal.set(tokens.refreshToken);
|
||||
this.claimsSignal.set(claims);
|
||||
this.statusSignal.set('authenticated');
|
||||
this.writeStorage(TOKEN_STORAGE_KEY, tokens.token);
|
||||
this.writeStorage(REFRESH_STORAGE_KEY, tokens.refreshToken);
|
||||
this.scheduleRefresh(claims);
|
||||
}
|
||||
getRefreshToken() {
|
||||
return this.refreshTokenSignal();
|
||||
}
|
||||
markExpired() {
|
||||
this.statusSignal.set('expired');
|
||||
this.clearRefreshTimer();
|
||||
}
|
||||
clear() {
|
||||
this.tokenSignal.set(null);
|
||||
this.refreshTokenSignal.set(null);
|
||||
this.claimsSignal.set(null);
|
||||
this.statusSignal.set('unauthenticated');
|
||||
this.removeStorage(TOKEN_STORAGE_KEY);
|
||||
this.removeStorage(REFRESH_STORAGE_KEY);
|
||||
this.clearRefreshTimer();
|
||||
}
|
||||
scheduleRefresh(claims) {
|
||||
this.clearRefreshTimer();
|
||||
const expiresInMs = claims.exp * 1000 - Date.now();
|
||||
const refreshInMs = Math.max(expiresInMs - REFRESH_SKEW_MS, 5_000);
|
||||
this.refreshTimer = setTimeout(() => this.refreshCallback?.(), refreshInMs);
|
||||
}
|
||||
clearRefreshTimer() {
|
||||
if (this.refreshTimer) {
|
||||
clearTimeout(this.refreshTimer);
|
||||
this.refreshTimer = undefined;
|
||||
}
|
||||
}
|
||||
readStorage(key) {
|
||||
return typeof localStorage === 'undefined' ? null : localStorage.getItem(key);
|
||||
}
|
||||
writeStorage(key, value) {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
}
|
||||
removeStorage(key) {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
SessionService = __decorate([
|
||||
Injectable({ providedIn: 'root' })
|
||||
], SessionService);
|
||||
export { SessionService };
|
||||
Reference in New Issue
Block a user