backblaze-b2
Advanced tools
Comparing version 1.3.1 to 1.4.0
@@ -1,8 +0,23 @@ | ||
### v1.2.0 (January 30, 2017) - The getBucket release | ||
### v1.4.0 (June 3, 2019) - The Application Key / Streams release | ||
Features | ||
- Add `applicationKeyId` parameter for proper use of application keys. (#67 - thanks @phil-r) | ||
- Add contentLength param to uploadFile, allowing the use of Streams when uploading. (#73 - thanks @jamiesyme) | ||
- Allow underscores in info headers. (#70 - thanks @odensc) | ||
### v1.3.1 (February 25, 2019) - The Axios control release | ||
Features | ||
- Automatic retries on request failure (customizable) | ||
- Complete control of the axios instance at the request level (axios and axiosOverride args) | ||
### v1.2.0 (January 30, 2019) - The getBucket release | ||
Features | ||
- Adds `B2.getBucket(...)` to help get bucket IDs with restricted bucket keys. In B2 v2, `B2.listBuckets()` will respond with an error, if you authorize without the `master key`. | ||
### v1.1.0 (January 27, 2017) - The B2 v2 release | ||
### v1.1.0 (January 27, 2019) - The B2 v2 release | ||
@@ -9,0 +24,0 @@ Features |
@@ -10,3 +10,3 @@ const _ = require('lodash'); | ||
_.get(args, 'axios', {}), | ||
getRequestOptions(b2.accountId, b2.applicationKey), | ||
getRequestOptions(b2), | ||
_.get(args, 'axiosOverride', {}) | ||
@@ -21,7 +21,7 @@ ); | ||
function getRequestOptions(accountId, applicationKey) { | ||
function getRequestOptions(b2) { | ||
return { | ||
url: conf.API_AUTHORIZE__URL, | ||
headers: utils.getAuthHeaderObject(accountId, applicationKey) | ||
headers: utils.getAuthHeaderObject(b2) | ||
}; | ||
} |
@@ -17,2 +17,3 @@ const _ = require('lodash'); | ||
const mime = args.mime; | ||
const len = args.contentLength || data.byteLength || data.length; | ||
@@ -25,3 +26,3 @@ const options = { | ||
'Content-Type': mime || 'b2/x-auto', | ||
'Content-Length': data.byteLength || data.length, | ||
'Content-Length': len, | ||
'X-Bz-File-Name': fileName, | ||
@@ -329,2 +330,2 @@ 'X-Bz-Content-Sha1': hash || (data ? sha1(data) : null) | ||
)); | ||
}; | ||
}; |
@@ -8,2 +8,3 @@ const axios = require('axios'); | ||
this.accountId = options.accountId; | ||
this.applicationKeyId = options.applicationKeyId; | ||
this.applicationKey = options.applicationKey; | ||
@@ -10,0 +11,0 @@ this.authorizationToken = null; |
@@ -21,3 +21,3 @@ const conf = require('../conf'); | ||
function isValidHeader(header) { | ||
return /^[a-z0-9-]+$/i.test(header); | ||
return /^[a-z0-9-_]+$/i.test(header); | ||
} | ||
@@ -24,0 +24,0 @@ |
@@ -17,10 +17,11 @@ /* global Buffer */ | ||
exports.getAuthHeaderObject = function(accountId, applicationKey) { | ||
if (!accountId) { | ||
throw new Error('Invalid accountId'); | ||
exports.getAuthHeaderObject = function(b2) { | ||
const id = b2.applicationKeyId || b2.accountId; | ||
if (!id) { | ||
throw new Error('Invalid accountId or applicationKeyId'); | ||
} | ||
if (!applicationKey) { | ||
if (!b2.applicationKey) { | ||
throw new Error('Invalid applicationKey'); | ||
} | ||
let base64 = Buffer.from(accountId + ':' + applicationKey).toString('base64'); | ||
let base64 = Buffer.from(id + ':' + b2.applicationKey).toString('base64'); | ||
return { | ||
@@ -27,0 +28,0 @@ Authorization: 'Basic ' + base64 |
{ | ||
"name": "backblaze-b2", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "Node.js Library for the Backblaze B2 Storage Service", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -27,3 +27,3 @@ # Backblaze B2 Node.js Library | ||
const b2 = new B2({ | ||
accountId: 'applicationKeyId', // or accountId | ||
applicationKeyId: 'applicationKeyId', // or accountId: 'accountId' | ||
applicationKey: 'applicationKey' // or masterApplicationKey | ||
@@ -72,3 +72,3 @@ }); | ||
const b2 = new B2({ | ||
accountId: 'applicationKeyId', // or accountId | ||
applicationKeyId: 'applicationKeyId', // or accountId: 'accountId' | ||
applicationKey: 'applicationKey', // or masterApplicationKey | ||
@@ -144,2 +144,3 @@ // optional: | ||
fileName: 'fileName', | ||
contentLength: 0, // optional data length, will default to data.byteLength or data.length if not provided | ||
mime: '', // optional mime type, will default to 'b2/x-auto' if not provided | ||
@@ -146,0 +147,0 @@ data: 'data', // this is expecting a Buffer, not an encoded string |
@@ -34,67 +34,113 @@ /* global describe, beforeEach, it */ | ||
beforeEach(function() { | ||
b2 = { | ||
accountId: 'unicorns', | ||
applicationKey: 'rainbows' | ||
}; | ||
}); | ||
describe('using accountId', function() { | ||
beforeEach(function() { | ||
b2 = { | ||
accountId: 'unicorns', | ||
applicationKey: 'rainbows' | ||
}; | ||
}); | ||
describe('with valid response', function() { | ||
beforeEach(function(done) { | ||
describe('with valid response', function() { | ||
beforeEach(function(done) { | ||
authResponse = { | ||
data: { | ||
authorizationToken: 'foo', | ||
apiUrl: 'https://foo', | ||
downloadUrl: 'https://bar' | ||
} | ||
}; | ||
authResponse = { | ||
data: { | ||
accountId: 'unicorns', | ||
authorizationToken: 'foo', | ||
apiUrl: 'https://foo', | ||
downloadUrl: 'https://bar' | ||
} | ||
}; | ||
// Resolve the promise that's set up above. | ||
deferred.resolve(authResponse); | ||
// Resolve the promise that's set up above. | ||
deferred.resolve(authResponse); | ||
auth.authorize(b2).then(function(response) { | ||
actualAuthResponse = response; | ||
done(); | ||
auth.authorize(b2).then(function(response) { | ||
actualAuthResponse = response; | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('Should set correct auth header in request options', function() { | ||
expect(actualAuthResponse).to.eql(authResponse); | ||
expect(requestOptions.headers).to.eql({ Authorization: 'Basic dW5pY29ybnM6cmFpbmJvd3M=' }); | ||
it('Should set correct auth header in request options', function() { | ||
expect(actualAuthResponse).to.eql(authResponse); | ||
expect(requestOptions.headers).to.eql({ Authorization: 'Basic dW5pY29ybnM6cmFpbmJvd3M=' }); | ||
}); | ||
it('Should set auth request options and set fields on valid b2 instance', function() { | ||
expect(b2.accountId).to.be('unicorns'); | ||
expect(b2.authorizationToken).to.be('foo'); | ||
expect(b2.apiUrl).to.be('https://foo'); | ||
expect(b2.downloadUrl).to.be('https://bar'); | ||
}); | ||
}); | ||
it('Should set auth request options and set fields on valid b2 instance', function() { | ||
expect(b2.authorizationToken).to.be('foo'); | ||
expect(b2.apiUrl).to.be('https://foo'); | ||
expect(b2.downloadUrl).to.be('https://bar'); | ||
describe('with error response', function() { | ||
var isRejected; | ||
var rejectedMessage; | ||
beforeEach(function(done) { | ||
errorMessage = 'Something went wrong'; | ||
isRejected = false; | ||
rejectedMessage = null; | ||
// Reject the promise that's set up above | ||
deferred.reject(errorMessage); | ||
auth.authorize(b2).then(null, function(error) { | ||
isRejected = true; | ||
rejectedMessage = error; | ||
done(); | ||
}); | ||
}); | ||
it('Should reject promise is error is received', function() { | ||
expect(isRejected).to.be(true); | ||
expect(rejectedMessage).to.be(errorMessage); | ||
}); | ||
}); | ||
}); | ||
describe('with error response', function() { | ||
var isRejected; | ||
var rejectedMessage; | ||
describe('using applicationId', function() { | ||
beforeEach(function() { | ||
b2 = { | ||
applicationKeyId: 'kittens', | ||
applicationKey: 'rainbows' | ||
}; | ||
}); | ||
beforeEach(function(done) { | ||
errorMessage = 'Something went wrong'; | ||
isRejected = false; | ||
rejectedMessage = null; | ||
describe('with valid response', function() { | ||
beforeEach(function(done) { | ||
// Reject the promise that's set up above | ||
deferred.reject(errorMessage); | ||
authResponse = { | ||
data: { | ||
accountId: 'unicorns', | ||
authorizationToken: 'foo', | ||
apiUrl: 'https://foo', | ||
downloadUrl: 'https://bar' | ||
} | ||
}; | ||
auth.authorize(b2).then(null, function(error) { | ||
isRejected = true; | ||
rejectedMessage = error; | ||
done(); | ||
// Resolve the promise that's set up above. | ||
deferred.resolve(authResponse); | ||
auth.authorize(b2).then(function(response) { | ||
actualAuthResponse = response; | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('Should reject promise is error is received', function() { | ||
expect(isRejected).to.be(true); | ||
expect(rejectedMessage).to.be(errorMessage); | ||
it('Should set correct auth header in request options', function() { | ||
expect(actualAuthResponse).to.eql(authResponse); | ||
expect(requestOptions.headers).to.eql({ Authorization: 'Basic a2l0dGVuczpyYWluYm93cw==' }); | ||
}); | ||
it('Should set auth request options and set fields on valid b2 instance', function() { | ||
expect(b2.accountId).to.be('unicorns'); | ||
expect(b2.authorizationToken).to.be('foo'); | ||
expect(b2.apiUrl).to.be('https://foo'); | ||
expect(b2.downloadUrl).to.be('https://bar'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -231,2 +231,19 @@ /* global describe, beforeEach, it */ | ||
describe('with contentLength specified', function() { | ||
beforeEach(function(done) { | ||
options.data = 'more than 3'; | ||
options.contentLength = 3; | ||
file.uploadFile(b2, options).then(function() { | ||
done(); | ||
}); | ||
}); | ||
it('should override Content-Length header', function() { | ||
expect(requestOptions.headers['Content-Length']).to.equal(3); | ||
}); | ||
}); | ||
}); | ||
@@ -233,0 +250,0 @@ |
@@ -29,3 +29,4 @@ /* global describe, beforeEach, it */ | ||
info = { | ||
foo: 'bar', | ||
under_score: 'under_score', | ||
foo: 'bar', | ||
unicorns: 'rainbows' | ||
@@ -37,2 +38,3 @@ }; | ||
expect(options.headers).to.eql({ | ||
'X-Bz-Info-under_score': 'under_score', | ||
'X-Bz-Info-foo': 'bar', | ||
@@ -39,0 +41,0 @@ 'X-Bz-Info-unicorns': 'rainbows' |
@@ -18,23 +18,36 @@ /* global describe, beforeEach, it */ | ||
describe('getAuthHeaderObject', function() { | ||
it('Should get header object with Base64 encoded Authorization header', function() { | ||
var accountId = 'unicorns'; | ||
var applicationKey = 'rainbows'; | ||
it('Should get header object with Base64 encoded Authorization header using accountId', function() { | ||
const b2 = { | ||
accountId: 'unicorns', | ||
applicationKey: 'rainbows' | ||
}; | ||
expect(utils.getAuthHeaderObject(b2)).to.eql({ Authorization: 'Basic dW5pY29ybnM6cmFpbmJvd3M=' }); | ||
}); | ||
expect(utils.getAuthHeaderObject(accountId, applicationKey)).to.eql({ Authorization: 'Basic dW5pY29ybnM6cmFpbmJvd3M=' }); | ||
it('Should get header object with Base64 encoded Authorization header using applicationKeyId', function() { | ||
const b2 = { | ||
applicationKeyId: 'unicorns', | ||
applicationKey: 'rainbows' | ||
}; | ||
expect(utils.getAuthHeaderObject(b2)).to.eql({ Authorization: 'Basic dW5pY29ybnM6cmFpbmJvd3M=' }); | ||
}); | ||
it('Should throw error given invalid accountId', function() { | ||
var applicationKey = 'rainbows'; | ||
it('Should throw error given invalid accountId or applicationKeyId', function() { | ||
const b2 = { | ||
applicationKey: 'rainbows' | ||
}; | ||
try { | ||
utils.getAuthHeaderObject(undefined, applicationKey); | ||
utils.getAuthHeaderObject(b2); | ||
} catch (e) { | ||
err = e; | ||
} | ||
expect(err.message).to.be('Invalid accountId'); | ||
expect(err.message).to.be('Invalid accountId or applicationKeyId'); | ||
}); | ||
it('Should throw error given invalid applicationKey', function() { | ||
var accountId = 'unicorns'; | ||
const b2 = { | ||
accountId: 'unicorns' | ||
}; | ||
try { | ||
utils.getAuthHeaderObject(accountId, undefined); | ||
utils.getAuthHeaderObject(b2); | ||
} catch (e) { | ||
@@ -41,0 +54,0 @@ err = e; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
2078
320
98099
26