Socket
Socket
Sign inDemoInstall

apple-music-token-node

Package Overview
Dependencies
16
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.1.1 to 2.0.0

.travis.yml

95

index.js

@@ -7,26 +7,4 @@ const jwt = require('jsonwebtoken');

/**
* @function getToken - Generates a developer token for use with the Apple Music API
* @param {string} certPath - Absolute path to your .p8 private key file
* @param {string} teamId - Developer team id
* @param {string} keyId - Music Key id
* @param {string} hoursValid - Hours until the key should expire
* @returns {{token: string, expiresAt: timestamp, expiresIn: seconds}} -
* ES256 encoded JWT token, time of expiration (in seconds), and also the seconds
* remaining until expiration occurs.
*
* (`expiresIn` is sort of a lazy solution on my part, but is included to avoid
* requiring anyone to deal with side-effects from date conversions between server
* and client code.)
*/
const getToken = (certPath, teamId, keyId, hoursValid = 12) => {
if (!fs.lstatSync(certPath).isFile()) {
throw new InvalidCertPathError(
{ certPath },
'Cert path provided to apple-music-token-node is not a valid file path',
);
}
const getResult = (cert, teamId, keyId, hoursValid) => {
const alg = 'ES256';
const cert = fs.readFileSync(certPath);
const now = moment().unix();

@@ -60,2 +38,71 @@ const expiration = moment().add(hoursValid, 'hours').unix();

module.exports = getToken;
/**
* @function getToken - Generates a developer token for use with the Apple Music API
* @param {string} certPath - Absolute path to your .p8 private key file
* @param {string} teamId - Developer team id
* @param {string} keyId - Music Key id
* @param {string} hoursValid - Hours until the key should expire
* @returns {{token: string, expiresAt: timestamp, expiresIn: seconds}} -
* ES256 encoded JWT token, time of expiration (in seconds), and also the seconds
* remaining until expiration occurs.
*
* (`expiresIn` is sort of a lazy solution on my part, but is included to avoid
* requiring anyone to deal with side-effects from date conversions between server
* and client code.)
*/
const getToken = (certPath, teamId, keyId, hoursValid = 12) => {
try {
if (!fs.lstatSync(certPath).isFile()) {
throw new InvalidCertPathError(
{ certPath },
'Cert path provided to apple-music-token-node is not a valid file path',
);
}
} catch (err) {
throw err;
}
const cert = fs.readFileSync(certPath);
return getResult(cert, teamId, keyId, hoursValid);
};
/**
* @function getTokenAsync - (Async) Generates a developer token for use with the Apple Music API
* @param {string} certPath - Absolute path to your .p8 private key file
* @param {string} teamId - Developer team id
* @param {string} keyId - Music Key id
* @param {string} hoursValid - Hours until the key should expire
* @returns {Promise} -
* Resolves to `{token: string, expiresAt: timestamp, expiresIn: seconds}` (ES256 encoded JWT token,
* time of expiration (in seconds), and also the seconds remaining until expiration occurs).
*/
const getTokenAsync = (certPath, teamId, keyId, hoursValid = 12) => {
return new Promise((resolve, reject) => {
fs.lstat(certPath, (err, stats) => {
if (err) {
return reject(err);
}
if (!stats.isFile()) {
return reject(new InvalidCertPathError(
{ certPath },
'Cert path provided to apple-music-token-node is not a valid file path',
));
}
fs.readFile(certPath, (err, cert) => {
if (err) {
return reject(err);
}
const result = getResult(cert, teamId, keyId, hoursValid);
return resolve(result);
});
});
});
};
module.exports.getToken = getToken;
module.exports.getTokenAsync = getTokenAsync;
const amtn = require('../index');
const { getToken } = amtn;
module.exports = (filePath, teamId, keyId, hoursValid) => {
try {
return amtn(filePath.trim(), teamId.trim(), keyId.trim(), hoursValid);
return getToken(filePath.trim(), teamId.trim(), keyId.trim(), hoursValid);
} catch (error) {

@@ -7,0 +9,0 @@ console.log(error);

{
"name": "apple-music-token-node",
"version": "1.1.1",
"version": "2.0.0",
"description": "generate developer tokens for the apple music api in node, with a CLI mode for development.",

@@ -31,13 +31,13 @@ "main": "index.js",

"dependencies": {
"jsonwebtoken": "^8.2.0",
"moment": "^2.21.0"
"jsonwebtoken": "^8.5.1",
"moment": "^2.24.0"
},
"devDependencies": {
"chai": "^4.1.2",
"chalk": "^2.4.1",
"chai": "^4.2.0",
"chalk": "^2.4.2",
"clear": "^0.1.0",
"figlet": "^1.2.0",
"inquirer": "^6.0.0",
"mocha": "^5.2.0"
"figlet": "^1.2.3",
"inquirer": "^6.5.0",
"mocha": "^6.2.0"
}
}

@@ -1,3 +0,5 @@

## apple music token generator for node
## apple music token node
[![Build Status](https://travis-ci.org/sheminusminus/apple-music-token-node.svg?branch=master)](https://travis-ci.org/sheminusminus/apple-music-token-node)
use javascript to generate your developer tokens for use with the apple music api.

@@ -9,2 +11,4 @@

npm
```

@@ -14,2 +18,7 @@ npm install -S apple-music-token-node

yarn
```
yarn add apple-music-token-node
```
-or-

@@ -19,2 +28,28 @@

### updating from v1.x to v2.x
if you don't want to use the async api available in v2, the only code change you need to make is to update from this:
```
const getToken = require('apple-music-token-node');
```
to this:
```
const { getToken } = require('apple-music-token-node');
```
and you're done!
if you *would* like to use the new async api, you can require it like so:
```
const { getTokenAsync } = require('apple-music-token-node');
```
`getTokenAsync` takes the same arguments as `getToken`, and returns a promise (and thus is usable with `async`/`await`). the promise resolves to the same object that would be returned by using `getToken`.
### usage

@@ -24,6 +59,7 @@

synchronous usage:
```
const path = require('path');
const getToken = require('apple-music-token-node');
const { getToken } = require('apple-music-token-node');

@@ -38,2 +74,29 @@ const { teamId, keyId } = require('./path-to-your-config');

asynchronous usage:
```
const path = require('path');
const { getTokenAsync } = require('apple-music-token-node');
const { teamId, keyId } = require('./path-to-your-config');
const certPath = path.resolve(__dirname, './path-to-your-p8-file');
const generate = async () => {
const tokenData = await getTokenAsync(certPath, teamId, keyId);
// tokenData == { token: 'generated_token', expiresAt: timeInSeconds }
// ...
};
// -or-
const generate = () => {
getTokenAsync(certPath, teamId, keyId).then((tokenData) => {
// tokenData == { token: 'generated_token', expiresAt: timeInSeconds }
// ...
});
};
```
### cli mode

@@ -43,2 +106,4 @@

npm
```

@@ -48,5 +113,11 @@ npm i -g apple-music-token-node

then you can run
yarn
```
yarn add -g apple-music-token-node
```
then you can run:
```
amtn

@@ -58,3 +129,3 @@ ```

![Data entered correctly:](https://i.imgur.com/Z9yXFte.png)
![Basic file path suggestion for incorrect entries:](https://i.imgur.com/nUunmcI.png)
![Data entered correctly](https://i.imgur.com/Z9yXFte.png)
![Basic file path suggestion for incorrect entries](https://i.imgur.com/nUunmcI.png)

@@ -6,38 +6,83 @@ const chai = require('chai');

const amtn = require('../index');
const InvalidCertPathError = require('../invalidCertPathError');
const config = require('./testData/config');
const { assert, expect } = chai;
const { assert } = chai;
const { getToken, getTokenAsync } = amtn;
const mockCertFile = './testData/APNsAuthKey_6F44JJ9SDF_com.example.FakeApp_UB40ZXKCDZ.p8';
describe('apple music token node', () => {
it('should exist', () => {
assert.isFunction(amtn);
describe('sync api', () => {
it('should exist', () => {
assert.isFunction(getToken);
});
it('should return an object `{ token, expiresAt }` for valid params', () => {
const validPath = path.resolve(__dirname, mockCertFile);
const tokenData = getToken(validPath, config.testTeamId, config.testKeyId, 1);
assert.isObject(tokenData);
assert.isString(tokenData.token);
assert.isNumber(tokenData.expiresAt);
});
it('if no `hoursValid` provided, should complete using 12h default', () => {
const validPath = path.resolve(__dirname, mockCertFile);
const { expiresAt } = getToken(validPath, config.testTeamId, config.testKeyId);
const soon = moment().add(13, 'hours');
const sooner = moment().add(11, 'hours');
assert.isTrue(moment.unix(expiresAt).isSameOrBefore(soon, 'hour'));
assert.isTrue(moment.unix(expiresAt).isSameOrAfter(sooner, 'hour'));
});
it('should throw an error if the certificate file does not exist', () => {
const invalidPath = path.resolve(__dirname, 'sex_panther.p8');
function throwing() {
getToken(invalidPath, config.testTeamId, config.testKeyId, 1);
}
assert.throws(throwing);
});
});
it('should return an object `{ token, expiresAt }` for valid params', () => {
const validPath = path.resolve(__dirname, mockCertFile);
const tokenData = amtn(validPath, config.testTeamId, config.testKeyId, 1);
assert.isObject(tokenData);
assert.isString(tokenData.token);
assert.isNumber(tokenData.expiresAt);
});
describe('async api', () => {
it('should exist', () => {
assert.isFunction(getTokenAsync);
});
it('if no `hoursValid` provided, should complete using 12h default', () => {
const validPath = path.resolve(__dirname, mockCertFile);
const { expiresAt } = amtn(validPath, config.testTeamId, config.testKeyId);
const soon = moment().add(13, 'hours');
const sooner = moment().add(11, 'hours');
assert.isTrue(moment.unix(expiresAt).isSameOrBefore(soon, 'hour'));
assert.isTrue(moment.unix(expiresAt).isSameOrAfter(sooner, 'hour'));
});
it('should return a promise', () => {
const validPath = path.resolve(__dirname, mockCertFile);
const tokenDataPromise = getTokenAsync(validPath, config.testTeamId, config.testKeyId, 1);
assert.instanceOf(tokenDataPromise, Promise, 'result is not a promise');
});
it('should throw an error if the certificate file does not exist', () => {
const invalidPath = path.resolve(__dirname, 'sex_panther.p8');
function throwing() {
amtn(invalidPath, config.testTeamId, config.testKeyId, 1);
}
assert.throws(throwing);
it('should resolve to an object `{ token, expiresAt }` for valid params', async () => {
const validPath = path.resolve(__dirname, mockCertFile);
const tokenData = await getTokenAsync(validPath, config.testTeamId, config.testKeyId, 1);
assert.isObject(tokenData);
assert.isString(tokenData.token);
assert.isNumber(tokenData.expiresAt);
});
it('if no `hoursValid` provided, should complete using 12h default', async () => {
const validPath = path.resolve(__dirname, mockCertFile);
const { expiresAt } = await getTokenAsync(validPath, config.testTeamId, config.testKeyId);
const soon = moment().add(13, 'hours');
const sooner = moment().add(11, 'hours');
assert.isTrue(moment.unix(expiresAt).isSameOrBefore(soon, 'hour'));
assert.isTrue(moment.unix(expiresAt).isSameOrAfter(sooner, 'hour'));
});
it('should reject/throw if the certificate file does not exist', async () => {
let err = null;
let result = null;
const invalidPath = path.resolve(__dirname, 'sex_panther.p8');
try {
result = await getTokenAsync(invalidPath, config.testTeamId, config.testKeyId, 1);
} catch (e) {
err = e;
}
assert.isNotNull(err);
assert.isNull(result);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc