forked from Yara724/api
added offline inquiry in system setting also fix some bugs
This commit is contained in:
@@ -30,6 +30,8 @@ interface CachedFanavaranAuth {
|
||||
authenticationToken: string;
|
||||
/** Epoch ms when the cached token should be refreshed. */
|
||||
expiresAt: number;
|
||||
/** Hash of auth fields used when this token was obtained. */
|
||||
authFingerprint: string;
|
||||
}
|
||||
|
||||
interface TenantBackoffState {
|
||||
@@ -178,6 +180,22 @@ export class FanavaranAuthService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable fingerprint of tenant auth. Any change (location, credentials, …)
|
||||
* forces a fresh GetAppToken+Login even before Tehran midnight.
|
||||
*/
|
||||
static authFingerprint(auth: FanavaranAuthConfig): string {
|
||||
return [
|
||||
auth.appName,
|
||||
auth.secret,
|
||||
auth.username,
|
||||
auth.password,
|
||||
auth.corpId,
|
||||
auth.contractId,
|
||||
auth.location,
|
||||
].join("|");
|
||||
}
|
||||
|
||||
assertNotInBackoff(clientKey: FanavaranClientKey): void {
|
||||
const remaining = this.getBackoffRemainingMs(clientKey);
|
||||
if (remaining <= 0) return;
|
||||
@@ -195,13 +213,16 @@ export class FanavaranAuthService {
|
||||
},
|
||||
): Promise<string> {
|
||||
this.assertNotInBackoff(clientKey);
|
||||
const fingerprint = FanavaranAuthService.authFingerprint(
|
||||
getFanavaranClientProfile(clientKey).auth,
|
||||
);
|
||||
|
||||
if (!options?.forceRefresh) {
|
||||
const memoryHit = this.readMemoryCache(clientKey);
|
||||
const memoryHit = this.readMemoryCache(clientKey, fingerprint);
|
||||
if (memoryHit) {
|
||||
return memoryHit;
|
||||
}
|
||||
const persisted = await this.readPersistedCache(clientKey);
|
||||
const persisted = await this.readPersistedCache(clientKey, fingerprint);
|
||||
if (persisted) {
|
||||
return persisted;
|
||||
}
|
||||
@@ -253,6 +274,7 @@ export class FanavaranAuthService {
|
||||
auditSession?: FanavaranAuditSession,
|
||||
): Promise<string> {
|
||||
const profile = getFanavaranClientProfile(clientKey);
|
||||
const fingerprint = FanavaranAuthService.authFingerprint(profile.auth);
|
||||
const appToken = await this.fetchAppToken(profile.auth, auditSession);
|
||||
const authenticationToken = await this.fetchLoginToken(
|
||||
appToken,
|
||||
@@ -261,7 +283,12 @@ export class FanavaranAuthService {
|
||||
);
|
||||
|
||||
const expiresAt = FanavaranAuthService.getNextMidnightExpiryMs();
|
||||
await this.persistToken(clientKey, authenticationToken, expiresAt);
|
||||
await this.persistToken(
|
||||
clientKey,
|
||||
authenticationToken,
|
||||
expiresAt,
|
||||
fingerprint,
|
||||
);
|
||||
this.clearBackoff(clientKey);
|
||||
this.logger.log(
|
||||
`[${clientKey}] Cached Fanavaran authenticationToken until ${new Date(
|
||||
@@ -271,25 +298,44 @@ export class FanavaranAuthService {
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
private readMemoryCache(clientKey: FanavaranClientKey): string | null {
|
||||
private readMemoryCache(
|
||||
clientKey: FanavaranClientKey,
|
||||
fingerprint: string,
|
||||
): string | null {
|
||||
const cached = this.tokenCache.get(clientKey);
|
||||
if (cached && cached.expiresAt > Date.now()) {
|
||||
if (!cached) {
|
||||
return null;
|
||||
}
|
||||
if (cached.authFingerprint !== fingerprint) {
|
||||
this.logger.log(
|
||||
`[${clientKey}] Auth config changed — discarding in-memory Fanavaran token`,
|
||||
);
|
||||
this.tokenCache.delete(clientKey);
|
||||
return null;
|
||||
}
|
||||
if (cached.expiresAt > Date.now()) {
|
||||
return cached.authenticationToken;
|
||||
}
|
||||
if (cached) {
|
||||
this.tokenCache.delete(clientKey);
|
||||
}
|
||||
this.tokenCache.delete(clientKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
private async readPersistedCache(
|
||||
clientKey: FanavaranClientKey,
|
||||
fingerprint: string,
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
const doc = await this.authTokenModel.findOne({ clientKey }).lean().exec();
|
||||
if (!doc?.authenticationToken || !doc.expiresAt) {
|
||||
return null;
|
||||
}
|
||||
if (!doc.authFingerprint || doc.authFingerprint !== fingerprint) {
|
||||
this.logger.log(
|
||||
`[${clientKey}] Auth config changed (or legacy token without fingerprint) — discarding persisted Fanavaran token`,
|
||||
);
|
||||
await this.authTokenModel.deleteOne({ clientKey }).exec();
|
||||
return null;
|
||||
}
|
||||
const expiresAt = new Date(doc.expiresAt).getTime();
|
||||
if (!(expiresAt > Date.now())) {
|
||||
await this.authTokenModel.deleteOne({ clientKey }).exec();
|
||||
@@ -298,6 +344,7 @@ export class FanavaranAuthService {
|
||||
this.tokenCache.set(clientKey, {
|
||||
authenticationToken: doc.authenticationToken,
|
||||
expiresAt,
|
||||
authFingerprint: doc.authFingerprint,
|
||||
});
|
||||
this.logger.log(
|
||||
`[${clientKey}] Reused persisted Fanavaran authenticationToken until ${new Date(
|
||||
@@ -318,8 +365,13 @@ export class FanavaranAuthService {
|
||||
clientKey: FanavaranClientKey,
|
||||
authenticationToken: string,
|
||||
expiresAt: number,
|
||||
authFingerprint: string,
|
||||
): Promise<void> {
|
||||
this.tokenCache.set(clientKey, { authenticationToken, expiresAt });
|
||||
this.tokenCache.set(clientKey, {
|
||||
authenticationToken,
|
||||
expiresAt,
|
||||
authFingerprint,
|
||||
});
|
||||
try {
|
||||
await this.authTokenModel
|
||||
.findOneAndUpdate(
|
||||
@@ -328,6 +380,7 @@ export class FanavaranAuthService {
|
||||
$set: {
|
||||
authenticationToken,
|
||||
expiresAt: new Date(expiresAt),
|
||||
authFingerprint,
|
||||
},
|
||||
},
|
||||
{ upsert: true, new: true },
|
||||
|
||||
Reference in New Issue
Block a user