@flowfuse/flowfuse
Version:
An open source low-code development platform
85 lines (72 loc) • 2.44 kB
JavaScript
const fs = require('fs')
const path = require('path')
const jwt = require('jsonwebtoken')
const LICENSE_ISSUER = 'FlowForge Inc.'
const MQTT_CLIENT_DEFAULT_ALLOWANCE = {
teams: 5,
enterprise: 20
}
class LicenseDetails {
constructor (license, claims) {
// this.license = license;
this.id = claims.id
this.version = claims.ver || ''
this.note = claims.note
this.organisation = claims.sub
this.validFrom = new Date(claims.nbf * 1000)
this.expiresAt = new Date(claims.exp * 1000)
this.dev = claims.dev
this.tier = claims.tier || 'enterprise'
this.users = claims.users || 0
if (Object.hasOwn(claims, 'instances')) {
this.instances = claims.instances || 0
} else {
this.projects = claims.projects || 0
this.devices = claims.devices || 0
}
this.teams = claims.teams || 0
this.mqttClients = claims.mqttClients || MQTT_CLIENT_DEFAULT_ALLOWANCE[this.tier] || 0
Object.freeze(this)
}
get valid () {
return this.validFrom > Date.now() && this.expiresAt < Date.now()
}
get expired () {
return this.expiresAt < Date.now()
}
}
function verifyLicenseWithKey (data, key) {
const publicKey = fs.readFileSync(path.join(__dirname, key))
return jwt.verify(data, publicKey, {
// We'll check the expiration ourselves instead of throwing an error (which in turn, permits us to start up)
ignoreExpiration: true,
algorithms: ['ES256'],
issuer: LICENSE_ISSUER
})
}
async function verifyLicense (data) {
let claims
try {
claims = verifyLicenseWithKey(data, 'flowforge-ee-public-key.pem')
} catch (err) {
// Failed to verify using production key, try the dev-only key
try {
claims = verifyLicenseWithKey(data, 'dev-public-key.pem')
} catch (err2) {
throw err
}
// We should turn on validation that anything signed with the dev keys also contain the `dev=true` claim
//
// if (!claims.dev) {
// throw new Error('Non-development license signed with development-only key')
// }
claims.dev = true
}
if (!claims.sub) {
throw new Error("License missing 'sub' claim")
}
return new LicenseDetails(data, claims)
}
module.exports = {
verifyLicense
}