New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

disconnect

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

disconnect - npm Package Compare versions

Comparing version 0.5.3 to 0.6.0

lib/oauth.js

7

HISTORY.md

@@ -0,1 +1,8 @@

0.6.0 / 2015-01-19
==================
* OAuth authentication is no longer embedded in `DiscogsClient`
* Added OAuth signature method configuration option
* Added support for the new `Discogs Auth` authentication methods
* Changed default OAuth signature method to `PLAINTEXT` due to problems with `HMAC-SHA1` + database search
0.5.3 / 2014-12-02

@@ -2,0 +9,0 @@ ==================

234

lib/client.js

@@ -6,7 +6,6 @@ 'use strict';

url = require('url'),
queryString = require('querystring'),
OAuth = require('oauth-1.0a'),
pkg = require('../package.json'),
error = require('./error.js'),
queue = require('./queue.js');
queue = require('./queue.js'),
util = require('./util.js');

@@ -16,19 +15,2 @@ module.exports = DiscogsClient;

/**
* Deep merge two objects and return the result
* @param {object} target - The target object (by reference!)
* @param {object} source - The source object
*/
var merge = function(target, source){
for(var key in source){
if(source[key] && (typeof source[key] === 'object')){
target[key] = merge((Array.isArray(source[key]) ? [] : {}), source[key]);
}else{
target[key] = source[key];
}
}
return target;
};
/**
* Default configuration

@@ -39,11 +21,4 @@ */

host: 'api.discogs.com',
oauthRequestUrl: 'https://api.discogs.com/oauth/request_token',
oauthAccessUrl: 'https://api.discogs.com/oauth/access_token',
oauthAuthorizeUrl: 'https://www.discogs.com/oauth/authorize',
port: 443,
customHeaders: {
'Accept': 'application/json; application/octet-stream',
'Accept-Encoding': 'gzip,deflate',
'User-Agent': 'DisConnectClient/'+pkg.version+' +'+pkg.homepage
}
userAgent: 'DisConnectClient/'+pkg.version+' +'+pkg.homepage
};

@@ -54,17 +29,33 @@

* @param {string} [userAgent] - The name of the user agent to use to make API calls
* @param {object} [oauth] - Optional OAuth data object
* @param {object} [auth] - Optional authorization data object
* @returns {DiscogsClient}
*/
function DiscogsClient(userAgent, oauth){
function DiscogsClient(userAgent, auth){
// Allow the class to be called as a function, returning an instance
if(!(this instanceof DiscogsClient)){
return new DiscogsClient(userAgent, oauth);
return new DiscogsClient(userAgent, auth);
}
// Set the custom UserAgent when provided
if(typeof userAgent === 'string'){ this.userAgent = userAgent; }
// Set the default configuration
this.config = util.merge({}, defaultConfig);
// Set the custom User Agent when provided
if(typeof userAgent === 'string'){
this.config.userAgent = userAgent;
}
// No userAgent provided, but instead we have an accessObject
if((arguments.length === 1) && (typeof userAgent === 'object')){ oauth = userAgent; }
// Set OAuth data when provided by making a shallow copy of the oauth parameter
this.oauth = (typeof oauth === 'object') ? merge({}, oauth) : {version: '1.0', signatureMethod: 'HMAC-SHA1', status: null};
if((arguments.length === 1) && (typeof userAgent === 'object')){ auth = userAgent; }
// Set auth data when provided
if(auth && (typeof auth === 'object')){
if(!auth.hasOwnProperty('method')){
auth.method = 'discogs';
}
if(!auth.hasOwnProperty('level')){
if(auth.userToken){
auth.level = 2;
}else if(auth.consumerKey && auth.consumerSecret){
auth.level = 1;
}
}
this.auth = util.merge({}, auth);
}
}

@@ -78,3 +69,3 @@

DiscogsClient.prototype.setConfig = function(customConfig){
this.customConfig = merge(merge({}, defaultConfig), customConfig);
util.merge(this.config, customConfig);
return this;

@@ -84,60 +75,14 @@ };

/**
* Get an OAuth request token from Discogs
* @param {string} consumerKey - The Discogs consumer key
* @param {string} consumerSecret - The Discogs consumer secret
* @param {string} callbackUrl - The url for redirection after obtaining the request token
* @param {function} [callback] - Callback function receiving the data
* @returns {DiscogsClient}
*/
DiscogsClient.prototype.getRequestToken = function(consumerKey, consumerSecret, callbackUrl, callback){
var oauth = this.oauth, config = (this.customConfig||defaultConfig), oa = new OAuth({consumer: {public: consumerKey, secret: consumerSecret}});
oauth.consumerKey = consumerKey;
oauth.consumerSecret = consumerSecret;
this._rawRequest({url: config.oauthRequestUrl+'?oauth_callback='+oa.percentEncode(callbackUrl)}, function(err, data){
if(!err && data){
data = queryString.parse(data);
oauth.token = data.oauth_token;
oauth.tokenSecret = data.oauth_token_secret;
oauth.authorizeUrl = config.oauthAuthorizeUrl+'?oauth_token='+data.oauth_token;
oauth.status = 'request';
}
if(typeof callback === 'function'){ callback(err, oauth); }
});
return this;
};
/**
* Get an OAuth access token from Discogs
* @param {string} verifier - The OAuth 1.0a verification code returned by Discogs
* @param {function} [callback] - Callback function receiving the data
* @returns {DiscogsClient}
*/
DiscogsClient.prototype.getAccessToken = function(verifier, callback){
var oauth = this.oauth, oa = new OAuth({consumer: {public: oauth.consumerKey, secret: oauth.consumerSecret}});
this._rawRequest({url: (this.customConfig||defaultConfig).oauthAccessUrl+'?oauth_verifier='+oa.percentEncode(verifier)}, function(err, data){
if(!err && data){
data = queryString.parse(data);
oauth.token = data.oauth_token;
oauth.tokenSecret = data.oauth_token_secret;
oauth.status = 'access';
delete oauth.authorizeUrl;
}
if(typeof callback === 'function'){ callback(err, oauth); }
});
return this;
};
/**
* Return whether OAuth authentication is complete i.e. there is a valis access token
* Return whether the client is authenticated for the optionally given access level
* @param {number} [level] - Optional authentication level
* @returns {boolean}
*/
DiscogsClient.prototype.authenticated = function(){
return (this.oauth.status === 'access');
DiscogsClient.prototype.authenticated = function(level){
level = level||0;
return (this.auth && (this.auth.level > 0) && (this.auth.level >= level));
};
/**
* Test OAuth authentication by getting the identity resource for the authenticated user
* Test authentication by getting the identity resource for the authenticated user
* @param {function} callback - Callback function receiving the data

@@ -147,3 +92,3 @@ */

DiscogsClient.prototype.identity = function(callback){
this.get({url:'/oauth/identity', requireAuth: true}, callback);
this.get({url: '/oauth/identity', authLevel: 2}, callback);
};

@@ -159,3 +104,10 @@

this.get('', function(err, data){
if(data){ data.disconnect = { version: pkg.version, userAgent: (self.userAgent||(self.customConfig||defaultConfig).customHeaders['User-Agent']) }; }
if(data){
data.disconnect = {
version: pkg.version,
userAgent: self.config.userAgent,
authMethod: (self.auth ? self.auth.method : 'none'),
authLevel: (self.auth ? self.auth.level : 0)
};
}
callback(err, data);

@@ -181,14 +133,13 @@ });

urlParts = url.parse(options.url),
encoding = options.encoding||'utf8',
config = (this.customConfig||defaultConfig);
encoding = options.encoding||'utf8';
// Build request headers
var headers = {
'Host': config.host,
'User-Agent': this.config.userAgent,
'Accept': 'application/json; application/octet-stream',
'Accept-Encoding': 'gzip,deflate',
'Host': this.config.host,
'Connection': 'close',
'Content-Length': 0
};
headers = merge(headers, config.customHeaders);
// Set custom user agent when present
if(this.userAgent){ headers['User-Agent'] = this.userAgent; }

@@ -202,8 +153,18 @@ // Add content headers for POST/PUT requests that contain data

// Add Authorization header when authenticated or in the process of authenticating
if(this.oauth.consumerKey){
var oa = new OAuth({consumer: {public: this.oauth.consumerKey, secret: this.oauth.consumerSecret}}),
fullUrl = (urlParts.protocol && urlParts.host) ? urlParts.href : 'https://'+config.host+urlParts.path,
authObj = oa.authorize({method: method, url: fullUrl}, {public: this.oauth.token, secret: this.oauth.tokenSecret});
headers['Authorization'] = oa.toHeader(authObj).Authorization;
// Add Authorization header when authenticated (or in the process of authenticating)
if(this.auth && (this.auth.consumerKey || this.auth.userToken)){
var authHeader = '';
if(this.auth.method === 'oauth'){
var OAuth = require('./oauth.js'),
fullUrl = (urlParts.protocol && urlParts.host) ? urlParts.href : 'https://'+this.config.host+urlParts.path;
authHeader = new OAuth(this.auth).toHeader(method, fullUrl);
}else if(this.auth.method === 'discogs'){
authHeader = 'Discogs';
if(this.auth.userToken){
authHeader += ' token='+this.auth.userToken;
}else if(this.auth.consumerKey){
authHeader += ' key='+this.auth.consumerKey+', secret='+this.auth.consumerSecret;
}
}
headers['Authorization'] = authHeader;
}

@@ -213,4 +174,4 @@

var options = {
host: urlParts.host||config.host,
port: urlParts.port||config.port,
host: urlParts.host||this.config.host,
port: urlParts.port||this.config.port,
path: urlParts.path,

@@ -223,5 +184,3 @@ method: method,

var req = https.request(options, function(res){
var data = '',
rateLimit = null,
add = function(chunk){ data += chunk.toString(); };
var data = '', rateLimit = null, add = function(chunk){ data += chunk.toString(); };

@@ -289,17 +248,32 @@ // Pass the data to the callback and pass an error on unsuccessful HTTP status

DiscogsClient.prototype._request = function(options, callback){
var self = this, hasCb = (typeof callback === 'function');
var self = this, hasCb = (typeof callback === 'function'),
doRequest = function(){
self._rawRequest(options, function(err, data, rateLimit){
if(data && ((typeof options === 'string') || options.json)){
data = JSON.parse(data);
}
if(hasCb){ callback(err, data, rateLimit); }
});
};
// By default, queue requests
if(!options.hasOwnProperty('queue')){
options.queue = true;
}
// By default, expect responses to be JSON
if(!options.hasOwnProperty('json')){
options.json = true;
}
// Check whether authentication is required
if(!options.requireAuth || this.authenticated()){
queue.add(function(err){ // Add API request to the execution queue
if(!err){
self._rawRequest(options, function(err, data, rateLimit){
if(data && ((typeof options === 'string') || (options.encoding !== 'binary'))){
data = JSON.parse(data);
}
if(hasCb){ callback(err, data, rateLimit); }
});
}else{ // Can't add to the queue because it's full
if(hasCb){ callback(err); }
}
});
if(!options.authLevel || this.authenticated(options.authLevel)){
if(options.queue){ // Add API request to the execution queue
queue.add(function(err){
if(!err){
doRequest();
}else{ // Can't add to the queue because it's full
if(hasCb){ callback(err); }
}
});
}else{ // Don't queue, just do the request
doRequest();
}
}else{

@@ -333,3 +307,3 @@ if(hasCb){ callback(new error.AuthError()); }

if(typeof options === 'string'){ options = {url: options}; }
return this._request(merge(options, {method: 'POST', data: data}), callback);
return this._request(util.merge(options, {method: 'POST', data: data}), callback);
};

@@ -347,3 +321,3 @@

if(typeof options === 'string'){ options = {url: options}; }
return this._request(merge(options, {method: 'PUT', data: data}), callback);
return this._request(util.merge(options, {method: 'PUT', data: data}), callback);
};

@@ -360,6 +334,16 @@

if(typeof options === 'string'){ options = {url: options}; }
return this._request(merge(options, {method: 'DELETE'}), callback);
return this._request(util.merge(options, {method: 'DELETE'}), callback);
};
/**
* Get an instance of the Discogs OAuth class
* @returns {DiscogsOAuth}
*/
DiscogsClient.prototype.oauth = function(){
var OAuth = require('./oauth.js');
return new OAuth(this.auth);
};
/**
* Expose the database functions and pass the current instance

@@ -366,0 +350,0 @@ * @returns {object}

@@ -21,3 +21,3 @@ 'use strict';

}else{ // Get a specific folder
if(client.authenticated() || (parseInt(folder, 10) === 0)){
if(client.authenticated(2) || (parseInt(folder, 10) === 0)){
url += '/'+folder;

@@ -39,3 +39,3 @@ client.get(url, callback);

collection.addFolder = function(user, name, callback){
client.post({url: '/users/'+util.escape(user)+'/collection/folders', requireAuth: true}, {name: name}, callback);
client.post({url: '/users/'+util.escape(user)+'/collection/folders', authLevel: 2}, {name: name}, callback);
};

@@ -52,3 +52,3 @@

collection.editFolder = function(user, folder, name, callback){
client.post({url: '/users/'+util.escape(user)+'/collection/folders/'+folder, requireAuth: true}, {name: name}, callback);
client.post({url: '/users/'+util.escape(user)+'/collection/folders/'+folder, authLevel: 2}, {name: name}, callback);
};

@@ -64,3 +64,3 @@

collection.deleteFolder = function(user, folder, callback){
client.delete({url: '/users/'+util.escape(user)+'/collection/folders/'+folder, requireAuth: true}, callback);
client.delete({url: '/users/'+util.escape(user)+'/collection/folders/'+folder, authLevel: 2}, callback);
};

@@ -77,3 +77,3 @@

collection.releases = function(user, folder, params, callback){
if(client.authenticated() || (parseInt(folder, 10) === 0)){
if(client.authenticated(2) || (parseInt(folder, 10) === 0)){
var path = '/users/'+util.escape(user)+'/collection/folders/'+folder+'/releases';

@@ -103,3 +103,3 @@ if((arguments.length === 3) && (typeof params === 'function')){

}
client.post({url: '/users/'+util.escape(user)+'/collection/folders/'+(folder||1)+'/releases/'+release, requireAuth: true}, null, callback);
client.post({url: '/users/'+util.escape(user)+'/collection/folders/'+(folder||1)+'/releases/'+release, authLevel: 2}, null, callback);
};

@@ -118,3 +118,3 @@

collection.editRelease = function(user, folder, release, instance, data, callback){
client.post({url: '/users/'+util.escape(user)+'/collection/folders/'+folder+'/releases/'+release+'/instances/'+instance, requireAuth: true}, data, callback);
client.post({url: '/users/'+util.escape(user)+'/collection/folders/'+folder+'/releases/'+release+'/instances/'+instance, authLevel: 2}, data, callback);
};

@@ -132,3 +132,3 @@

collection.removeRelease = function(user, folder, release, instance, callback){
client.delete({url: '/users/'+util.escape(user)+'/collection/folders/'+folder+'/releases/'+release+'/instances/'+instance, requireAuth: true}, callback);
client.delete({url: '/users/'+util.escape(user)+'/collection/folders/'+folder+'/releases/'+release+'/instances/'+instance, authLevel: 2}, callback);
};

@@ -135,0 +135,0 @@

@@ -95,3 +95,3 @@ 'use strict';

database.image = function(file, callback){
client.get({url: '/images/'+file, encoding: 'binary', requireAuth: true}, callback);
client.get({url: '/images/'+file, encoding: 'binary', authLevel: 2, json: false}, callback);
};

@@ -114,3 +114,3 @@

obj.q = util.escape(query);
client.get({url: util.addParams('/database/search', obj), requireAuth: true}, callback);
client.get({url: util.addParams('/database/search', obj), authLevel: 1}, callback);
};

@@ -117,0 +117,0 @@

@@ -31,3 +31,3 @@ 'use strict';

marketplace.addListing = function(data, callback){
client.post({url: '/marketplace/listings', requireAuth: true}, data, callback);
client.post({url: '/marketplace/listings', authLevel: 2}, data, callback);
};

@@ -43,3 +43,3 @@

marketplace.editListing = function(listing, data, callback){
client.post({url: '/marketplace/listings/'+listing, requireAuth: true}, data, callback);
client.post({url: '/marketplace/listings/'+listing, authLevel: 2}, data, callback);
};

@@ -54,3 +54,3 @@

marketplace.deleteListing = function(listing, callback){
client.delete({url: '/marketplace/listings/'+listing, requireAuth: true}, callback);
client.delete({url: '/marketplace/listings/'+listing, authLevel: 2}, callback);
};

@@ -75,3 +75,3 @@

}
client.get({url: path, requireAuth: true}, callback);
client.get({url: path, authLevel: 2}, callback);
};

@@ -87,3 +87,3 @@

marketplace.editOrder = function(order, data, callback){
client.post({url: '/marketplace/orders/'+order, requireAuth: true}, data, callback);
client.post({url: '/marketplace/orders/'+order, authLevel: 2}, data, callback);
};

@@ -105,3 +105,3 @@

}
client.get({url: path, requireAuth: true}, callback);
client.get({url: path, authLevel: 2}, callback);
};

@@ -117,3 +117,3 @@

marketplace.orderAddMessage = function(order, data, callback){
client.post({url: '/marketplace/orders/'+order+'/messages', requireAuth: true}, data, callback);
client.post({url: '/marketplace/orders/'+order+'/messages', authLevel: 2}, data, callback);
};

@@ -145,3 +145,3 @@

marketplace.suggestPrice = function(release, callback){
client.get({url: '/marketplace/price_suggestions/'+release, requireAuth: true}, callback);
client.get({url: '/marketplace/price_suggestions/'+release, authLevel: 2}, callback);
};

@@ -148,0 +148,0 @@

@@ -45,2 +45,20 @@ 'use strict';

return queryString.escape(str);
};
/**
* Deep merge two objects
* @param {object} target - The target object (by reference!)
* @param {object} source - The source object
* @returns {object}
*/
util.merge = function(target, source){
for(var key in source){
if(source[key] && (typeof source[key] === 'object')){
target[key] = merge((Array.isArray(source[key]) ? [] : {}), source[key]);
}else{
target[key] = source[key];
}
}
return target;
};

@@ -39,3 +39,3 @@ 'use strict';

}
client.put({url: '/users/'+util.escape(user)+'/wants/'+release, requireAuth: true}, _data, callback);
client.put({url: '/users/'+util.escape(user)+'/wants/'+release, authLevel: 2}, _data, callback);
};

@@ -52,3 +52,3 @@

wantlist.editNotes = function(user, release, data, callback){
client.put({url: '/users/'+util.escape(user)+'/wants/'+release, requireAuth: true}, data, callback);
client.put({url: '/users/'+util.escape(user)+'/wants/'+release, authLevel: 2}, data, callback);
};

@@ -64,3 +64,3 @@

wantlist.removeRelease = function(user, release, callback){
client.delete({url: '/users/'+util.escape(user)+'/wants/'+release, requireAuth: true}, callback);
client.delete({url: '/users/'+util.escape(user)+'/wants/'+release, authLevel: 2}, callback);
};

@@ -67,0 +67,0 @@

{
"name": "disconnect",
"description": "An easy to use client library to connect with the discogs.com API v2.0",
"version": "0.5.3",
"version": "0.6.0",
"keywords": ["discogs", "api", "client", "oauth"],

@@ -6,0 +6,0 @@ "homepage": "https://github.com/bartve/disconnect",

@@ -11,3 +11,4 @@ ## About

* Supports [pagination](http://www.discogs.com/developers/#page:home,header:home-pagination), [rate limiting](http://www.discogs.com/developers/#page:home,header:home-rate-limiting), etc.
* All functions implement a standard `function(err, data, rateLimit)` format for the callback
* All database, marketplace and user functions implement a standard `function(err, data, rateLimit)` format for the callback
* Easy access to protected endpoints with `Discogs Auth`
* Includes OAuth 1.0a tools. Just plug in your consumer key and secret and do the OAuth dance

@@ -27,3 +28,4 @@ * API functions grouped in their own namespace for easy access and isolation

```
require('disconnect') -> new Client() -> database()
require('disconnect') -> new Client() -> oauth()
-> database()
-> marketplace()

@@ -34,8 +36,2 @@ -> user() -> collection()

```
To get the user wantlist functions:
```javascript
var Discogs = require('disconnect').Client;
var wantlist = new Discogs().user().wantlist();
```
More examples below.

@@ -54,9 +50,7 @@ ## Usage

Get release data. Note that in the following examples the `app` variable is an [Express instance](http://expressjs.com/starter/hello-world.html) to handle incoming HTTP requests.
Get the release data for a release with the id 176126.
```javascript
app.get('/release/:id', function(req, res){
var db = new Discogs().database();
db.release(req.params.id, function(err, data){
res.send(data);
});
var db = new Discogs().database();
db.release(176126, function(err, data){
console.log(data);
});

@@ -70,15 +64,31 @@ ```

Get page 2 of a user's public collection showing 75 releases.
Get page 2 of USER_NAME's public collection showing 75 releases.
The second param is the collection folder ID where 0 is always the "All" folder.
```javascript
app.get('/collection/:user', function(req, res){
var col = new Discogs().user().collection();
col.releases(req.params.user, 0, {page:2, per_page:75}, function(err, data){
res.send(data);
});
var col = new Discogs().user().collection();
col.releases('USER_NAME', 0, {page: 2, per_page: 75}, function(err, data){
console.log(data);
});
```
### Discogs Auth
Just provide the client constructor with your preferred way of [authentication](http://www.discogs.com/developers/#page:authentication).
```javascript
// Authenticate by user token
var dis = new Discogs({userToken: 'YOUR_USER_TOKEN'});
// Authenticate by consumer key and secret
var dis = new Discogs({
consumerKey: 'YOUR_CONSUMER_KEY',
consumerSecret: 'YOUR_CONSUMER_SECRET'
});
```
The User-Agent can still be passed for authenticated calls.
```javascript
var dis = new Discogs('MyUserAgent/1.0', {userToken: 'YOUR_USER_TOKEN'});
```
### OAuth
Below are the steps that involve getting a valid OAuth access token from Discogs.
Below are the steps that involve getting a valid OAuth access token from Discogs. Note that in the following examples the `app` variable is an [Express instance](http://expressjs.com/starter/hello-world.html) to handle incoming HTTP requests.

@@ -88,4 +98,4 @@ #### 1. Get a request token

app.get('/authorize', function(req, res){
var dis = new Discogs();
dis.getRequestToken(
var oAuth = new Discogs().oauth();
oAuth.getRequestToken(
'YOUR_CONSUMER_KEY',

@@ -108,4 +118,4 @@ 'YOUR_CONSUMER_SECRET',

app.get('/callback', function(req, res){
var dis = new Discogs(requestData);
dis.getAccessToken(
var oAuth = new Discogs(requestData).oauth();
oAuth.getAccessToken(
req.query.oauth_verifier, // Verification code sent back by Discogs

@@ -130,6 +140,2 @@ function(err, accessData){

```
The User-Agent may still be passed for OAuth calls.
```javascript
var dis = new Discogs('MyUserAgent/1.0', accessData);
```

@@ -139,12 +145,9 @@ ### Images

```javascript
app.get('/image/:filename', function(req, res){
var db = new Discogs(accessData).database(),
file = req.params.filename;
db.image(file, function(err, data, rateLimit){
// Data contains the raw binary image data
require('fs').writeFile(file, data, 'binary', function(err){
// See your current limits
console.log(rateLimit);
res.send('Image saved!');
});
var db = new Discogs(accessData).database(), file = 'R-176126-1322456477.jpeg';
db.image(file, function(err, data, rateLimit){
// Data contains the raw binary image data
require('fs').writeFile(file, data, 'binary', function(err){
// See your current limits
console.log(rateLimit);
console.log('Image saved!');
});

@@ -151,0 +154,0 @@ });

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc