node-playready
v1.1.1
Published
NodeJS Playready Client
Maintainers
Readme
node-playready
A lightweight NodeJS library for working with Microsoft PlayReady
- Loading and provisioning device certificates (bgroupcert + zgpriv - PRD v2/v3)
- Generating PlayReady license acquisition challenges (LA_URL / WRMHEADER)
- Parsing and decrypting PlayReady license responses (XMR)
- Unpacking PlayReady V3 PRD device files
- Inspecting PSSHs for PlayReady WRMHeader structures
Installation
npm:
npm install node-playreadypnpm:
pnpm install node-playreadybun:
bun add node-playreadyyarn:
yarn add node-playreadyUsage
import { readFileSync } from "fs";
import Playready from "node-playready";
// Read bgroupcert file
const bgroupcert = readFileSync("./bgroupcert.dat");
// Read zgpriv file
const zgpriv = readFileSync("./zgpriv.dat");
// Initialize Playready client
const device = Playready.init(bgroupcert, zgpriv)
// Get Device info
console.log(device.info)
// PSSH found in the MPD manifest
const pssh = Buffer.from(
"AAADfHBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAA1xcAwAAAQABAFIDPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4A
cwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AM
gAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMA
AuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAA
vAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBD
AFQASQBOAEYATwA+ADwASwBJAEQAPgA0AFIAcABsAGIAKwBUAGIATgBFAFMAOAB0AEcAawBOAEYAVwBUAEUASABBAD0APQA8A
C8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEsATABqADMAUQB6AFEAUAAvAE4AQQA9ADwALwBDAEgARQBDAEsAUwBVAE
0APgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAHAAcgBvAGYAZgBpAGMAaQBhAGwAcwBpAHQAZQAuAGsAZQB5AGQ
AZQBsAGkAdgBlAHIAeQAuAG0AZQBkAGkAYQBzAGUAcgB2AGkAYwBlAHMALgB3AGkAbgBkAG8AdwBzAC4AbgBlAHQALwBQAGwA
YQB5AFIAZQBhAGQAeQAvADwALwBMAEEAXwBVAFIATAA+ADwAQwBVAFMAVABPAE0AQQBUAFQAUgBJAEIAVQBUAEUAUwA+ADwAS
QBJAFMAXwBEAFIATQBfAFYARQBSAFMASQBPAE4APgA4AC4AMQAuADIAMwAwADQALgAzADEAPAAvAEkASQBTAF8ARABSAE0AXw
BWAEUAUgBTAEkATwBOAD4APAAvAEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AC8ARABBAFQAQQA+ADwALwB
XAFIATQBIAEUAQQBEAEUAUgA+AA==",
"base64"
);
// Generate Challenge
const challenge = device.generateChallenge(pssh);
// License Server URL
const licenseUrl = "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:2000)";
// License Request
const response = await fetch(licenseUrl, {
method: "POST",
headers: {
'Content-Type': 'text/xml; charset=UTF-8'
},
body: challenge
});
// Check if request was successful
if (response.ok) {
// Parse license
const successful = device.parseLicense(Buffer.from(await response.text(), 'utf-8')).length > 0
console.log(`successful? ${successful ? 'yes' : 'no'}`)
} else {
console.error('Request failed!')
console.log(await response.text())
}Usage with PRD files
WARNING: This function does not reprovision the PRD file, if you have a V3 PRD device please use the unpackV3PRD function and init the client with Playready.init()
import { readFileSync } from "fs";
import Playready from "node-playready";
// Read PRD file
const prd = readFileSync("./device.prd");
// Initialize Playready client
const device = Playready.initPRD(prd)
// Get Device info
console.log(device.info)
// PSSH found in the MPD manifest
const pssh = Buffer.from(
"AAADfHBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAA1xcAwAAAQABAFIDPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4A
cwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AM
gAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMA
AuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAA
vAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBD
AFQASQBOAEYATwA+ADwASwBJAEQAPgA0AFIAcABsAGIAKwBUAGIATgBFAFMAOAB0AEcAawBOAEYAVwBUAEUASABBAD0APQA8A
C8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEsATABqADMAUQB6AFEAUAAvAE4AQQA9ADwALwBDAEgARQBDAEsAUwBVAE
0APgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAHAAcgBvAGYAZgBpAGMAaQBhAGwAcwBpAHQAZQAuAGsAZQB5AGQ
AZQBsAGkAdgBlAHIAeQAuAG0AZQBkAGkAYQBzAGUAcgB2AGkAYwBlAHMALgB3AGkAbgBkAG8AdwBzAC4AbgBlAHQALwBQAGwA
YQB5AFIAZQBhAGQAeQAvADwALwBMAEEAXwBVAFIATAA+ADwAQwBVAFMAVABPAE0AQQBUAFQAUgBJAEIAVQBUAEUAUwA+ADwAS
QBJAFMAXwBEAFIATQBfAFYARQBSAFMASQBPAE4APgA4AC4AMQAuADIAMwAwADQALgAzADEAPAAvAEkASQBTAF8ARABSAE0AXw
BWAEUAUgBTAEkATwBOAD4APAAvAEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AC8ARABBAFQAQQA+ADwALwB
XAFIATQBIAEUAQQBEAEUAUgA+AA==",
"base64"
);
// Generate Challenge
const challenge = device.generateChallenge(pssh);
// License Server URL
const licenseUrl = "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:2000)";
// License Request
const response = await fetch(licenseUrl, {
method: "POST",
headers: {
'Content-Type': 'text/xml; charset=UTF-8'
},
body: challenge
});
// Check if request was successful
if (response.ok) {
// Parse license
const successful = device.parseLicense(Buffer.from(await response.text(), 'utf-8')).length > 0
console.log(`successful? ${successful ? 'yes' : 'no'}`)
} else {
console.error('Request failed!')
console.log(await response.text())
}unpackV3PRD
Unpacks a PlayReady V3 PRD device file.
This function returns the group certificate and group key needed for Playready.init()
import { readFileSync } from 'fs'
import Playready from 'node-playready'
const prd = readFileSync('./device.prd')
const { bgroupcert, zgpriv } = Playready.unpackV3PRD(prd)
console.log('bgroupcert length:', bgroupcert.length)
console.log('zgpriv length:', zgpriv.length)
// Initialize from PRD
const device = Playready.init(bgroupcert, zgpriv)
console.log(device.info)containsWRMHeader
Checks if a given Base64 string or raw buffer contains a valid PlayReady WRMHeader.
import Playready from "node-playready";
const pssh = Buffer.from(
"AAADfHBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAA1xcAwAAAQABAFIDPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4A
cwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AM
gAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMA
AuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAA
vAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBD
AFQASQBOAEYATwA+ADwASwBJAEQAPgA0AFIAcABsAGIAKwBUAGIATgBFAFMAOAB0AEcAawBOAEYAVwBUAEUASABBAD0APQA8A
C8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEsATABqADMAUQB6AFEAUAAvAE4AQQA9ADwALwBDAEgARQBDAEsAUwBVAE
0APgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAHAAcgBvAGYAZgBpAGMAaQBhAGwAcwBpAHQAZQAuAGsAZQB5AGQ
AZQBsAGkAdgBlAHIAeQAuAG0AZQBkAGkAYQBzAGUAcgB2AGkAYwBlAHMALgB3AGkAbgBkAG8AdwBzAC4AbgBlAHQALwBQAGwA
YQB5AFIAZQBhAGQAeQAvADwALwBMAEEAXwBVAFIATAA+ADwAQwBVAFMAVABPAE0AQQBUAFQAUgBJAEIAVQBUAEUAUwA+ADwAS
QBJAFMAXwBEAFIATQBfAFYARQBSAFMASQBPAE4APgA4AC4AMQAuADIAMwAwADQALgAzADEAPAAvAEkASQBTAF8ARABSAE0AXw
BWAEUAUgBTAEkATwBOAD4APAAvAEMAVQBTAFQATwBNAEEAVABUAFIASQBCAFUAVABFAFMAPgA8AC8ARABBAFQAQQA+ADwALwB
XAFIATQBIAEUAQQBEAEUAUgA+AA==",
"base64"
);
if (Playready.containsWRMHeader(pssh)) {
console.log("Valid PlayReady WRMHeader detected!");
} else {
console.log("No WRMHeader found.");
}