mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-18 18:23:18 +02:00
Refactor license key validation and recheck logic to improve error handling and maintain cache integrity
This commit is contained in:
@@ -104,11 +104,18 @@ LQIDAQAB
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async forceRecheck() {
|
public async forceRecheck() {
|
||||||
this.statusCache.flushAll();
|
|
||||||
this.licenseKeyCache.flushAll();
|
|
||||||
this.phoneHomeFailureCount = 0;
|
this.phoneHomeFailureCount = 0;
|
||||||
|
|
||||||
return await this.check();
|
// Force a fresh check without discarding the last known good cache
|
||||||
|
// up front — check() only replaces the cache once it has a fresh
|
||||||
|
// result, so a failed recheck (e.g. a transient server error) won't
|
||||||
|
// leave listKeys()/status looking empty in the meantime.
|
||||||
|
this.doRecheck = true;
|
||||||
|
try {
|
||||||
|
return await this.check();
|
||||||
|
} finally {
|
||||||
|
this.doRecheck = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async isUnlocked(): Promise<boolean> {
|
public async isUnlocked(): Promise<boolean> {
|
||||||
@@ -181,10 +188,15 @@ LQIDAQAB
|
|||||||
}
|
}
|
||||||
|
|
||||||
let foundHostKey = false;
|
let foundHostKey = false;
|
||||||
|
// Keys that fully decrypted, to phone home with. A row that
|
||||||
|
// fails to decrypt (e.g. stored under a different server
|
||||||
|
// secret) is marked invalid below but excluded here, so it
|
||||||
|
// can't take down validation for every other key in the batch.
|
||||||
|
const keys: { licenseKey: string; instanceId: string }[] = [];
|
||||||
// Validate stored license keys
|
// Validate stored license keys
|
||||||
for (const key of allKeysRes) {
|
for (const key of allKeysRes) {
|
||||||
try {
|
try {
|
||||||
// Decrypt the license key and token
|
// Decrypt the license key, token, and instance ID
|
||||||
const decryptedKey = decrypt(
|
const decryptedKey = decrypt(
|
||||||
key.licenseKeyId,
|
key.licenseKeyId,
|
||||||
this.serverSecret
|
this.serverSecret
|
||||||
@@ -193,6 +205,10 @@ LQIDAQAB
|
|||||||
key.token,
|
key.token,
|
||||||
this.serverSecret
|
this.serverSecret
|
||||||
);
|
);
|
||||||
|
const decryptedInstanceId = decrypt(
|
||||||
|
key.instanceId,
|
||||||
|
this.serverSecret
|
||||||
|
);
|
||||||
|
|
||||||
const payload = validateJWT<TokenPayload>(
|
const payload = validateJWT<TokenPayload>(
|
||||||
decryptedToken,
|
decryptedToken,
|
||||||
@@ -214,6 +230,11 @@ LQIDAQAB
|
|||||||
if (payload.type === "host") {
|
if (payload.type === "host") {
|
||||||
foundHostKey = true;
|
foundHostKey = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keys.push({
|
||||||
|
licenseKey: decryptedKey,
|
||||||
|
instanceId: decryptedInstanceId
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Error validating license key: ${key.licenseKeyId}`
|
`Error validating license key: ${key.licenseKeyId}`
|
||||||
@@ -233,37 +254,36 @@ LQIDAQAB
|
|||||||
status.isHostLicensed = false;
|
status.isHostLicensed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = allKeysRes.map((key) => ({
|
|
||||||
licenseKey: decrypt(key.licenseKeyId, this.serverSecret),
|
|
||||||
instanceId: decrypt(key.instanceId, this.serverSecret)
|
|
||||||
}));
|
|
||||||
|
|
||||||
let apiResponse: ValidateLicenseAPIResponse | undefined;
|
let apiResponse: ValidateLicenseAPIResponse | undefined;
|
||||||
try {
|
if (keys.length > 0) {
|
||||||
// Phone home to validate license keys
|
try {
|
||||||
apiResponse = await this.phoneHome(keys, false);
|
// Phone home to validate license keys
|
||||||
|
apiResponse = await this.phoneHome(keys, false);
|
||||||
|
|
||||||
if (!apiResponse?.success) {
|
if (!apiResponse?.success) {
|
||||||
throw new Error(apiResponse?.error);
|
throw new Error(apiResponse?.error);
|
||||||
}
|
}
|
||||||
// Reset failure count on success
|
// Reset failure count on success
|
||||||
this.phoneHomeFailureCount = 0;
|
this.phoneHomeFailureCount = 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.phoneHomeFailureCount++;
|
this.phoneHomeFailureCount++;
|
||||||
if (this.phoneHomeFailureCount === 1) {
|
if (this.phoneHomeFailureCount === 1) {
|
||||||
// First failure: fail silently
|
// First failure: fail silently
|
||||||
logger.error("Error communicating with license server:");
|
logger.error(
|
||||||
logger.error(e);
|
"Error communicating with license server:"
|
||||||
logger.error(
|
);
|
||||||
`Allowing failure. Will retry one more time at next run interval.`
|
logger.error(e);
|
||||||
);
|
logger.error(
|
||||||
// return last known good status
|
`Allowing failure. Will retry one more time at next run interval.`
|
||||||
return this.statusCache.get(
|
);
|
||||||
this.statusKey
|
// return last known good status
|
||||||
) as LicenseStatus;
|
return this.statusCache.get(
|
||||||
} else {
|
this.statusKey
|
||||||
// Subsequent failures: fail abruptly
|
) as LicenseStatus;
|
||||||
throw e;
|
} else {
|
||||||
|
// Subsequent failures: fail abruptly
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user