Initial public commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
// Action: "Check license status" — re-verifies the stored key (offline +
|
||||
// online) and refreshes `license_last_status`. Useful for diagnosing a
|
||||
// suddenly-rejecting app.
|
||||
|
||||
import { sdk } from '../sdk'
|
||||
import { Verifier, PublicKey, Client } from '@keysat/licensing-client'
|
||||
import {
|
||||
LICENSING_BASE_URL,
|
||||
LICENSING_BASE_URL_TOR,
|
||||
PRODUCT_SLUG,
|
||||
ISSUER_PUBKEY_PEM,
|
||||
PRODUCT_DISPLAY_NAME,
|
||||
} from '../licensing/config'
|
||||
|
||||
export const checkLicense = sdk.Action.withoutInput(
|
||||
'check-license',
|
||||
async ({ effects }) => ({
|
||||
name: 'Check license status',
|
||||
description:
|
||||
`Re-run signature and server-side checks against the currently ` +
|
||||
`stored license key for ${PRODUCT_DISPLAY_NAME}.`,
|
||||
warning: null,
|
||||
allowedStatuses: 'any',
|
||||
group: 'License',
|
||||
visibility: 'enabled',
|
||||
}),
|
||||
async ({ effects }) => {
|
||||
const store = await sdk.store.getOwn(effects, sdk.StorePath).const()
|
||||
const key = (store as { license_key: string | null }).license_key
|
||||
if (!key) {
|
||||
return {
|
||||
message:
|
||||
`No license key is stored. Run "Activate license" or "Buy license" first.`,
|
||||
}
|
||||
}
|
||||
|
||||
// Offline
|
||||
let offline
|
||||
try {
|
||||
offline = new Verifier(PublicKey.fromPem(ISSUER_PUBKEY_PEM)).verify(key)
|
||||
} catch (e) {
|
||||
await sdk.store.getOwn(effects, sdk.StorePath).merge({
|
||||
license_last_status: `offline-invalid: ${errMsg(e)}`,
|
||||
})
|
||||
return {
|
||||
message:
|
||||
`The stored key no longer verifies cryptographically. This means ` +
|
||||
`the key was edited, truncated, or the issuer public key was ` +
|
||||
`rotated by the seller. Contact the seller.\n\nDetails: ${errMsg(e)}`,
|
||||
}
|
||||
}
|
||||
|
||||
// Online
|
||||
let onlineLine: string
|
||||
try {
|
||||
const client = await firstReachableClient()
|
||||
const r = await client.validate(key, PRODUCT_SLUG, undefined)
|
||||
onlineLine = r.ok
|
||||
? 'Server says: OK'
|
||||
: `Server rejected the key: ${r.reason ?? 'unknown'}`
|
||||
await sdk.store.getOwn(effects, sdk.StorePath).merge({
|
||||
license_last_status: r.ok ? 'valid (online-checked)' : `rejected: ${r.reason ?? 'unknown'}`,
|
||||
})
|
||||
} catch (_) {
|
||||
onlineLine = 'Server: unreachable (offline — relying on signature only)'
|
||||
}
|
||||
|
||||
return {
|
||||
message:
|
||||
`Signature: OK\n` +
|
||||
`${onlineLine}\n\n` +
|
||||
`Product: ${offline.productId}\n` +
|
||||
`License id: ${offline.licenseId}\n` +
|
||||
`Issued at: ${offline.payload.issuedAt}`,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
async function firstReachableClient(): Promise<Client> {
|
||||
const urls = [LICENSING_BASE_URL, LICENSING_BASE_URL_TOR].filter(Boolean) as string[]
|
||||
for (const base of urls) {
|
||||
const client = new Client(base)
|
||||
try {
|
||||
await client.fetchPubkeyPem()
|
||||
return client
|
||||
} catch (_) {}
|
||||
}
|
||||
throw new Error('no reachable URL')
|
||||
}
|
||||
|
||||
function errMsg(e: unknown): string {
|
||||
return e instanceof Error ? e.message : String(e)
|
||||
}
|
||||
Reference in New Issue
Block a user