shadowsocks-manager
Version:
A shadowsocks manager tool for multi user and traffic control.
173 lines (151 loc) • 5.44 kB
JavaScript
const crypto = require('crypto');
const get = require('simple-get');
const OAuth = require('oauth-1.0a');
const querystring = require('querystring');
const TW_REQ_TOKEN_URL = 'https://api.twitter.com/oauth/request_token';
const TW_AUTH_URL = 'https://api.twitter.com/oauth/authenticate';
const TW_ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token';
class LoginWithTwitter {
constructor (opts) {
if (!opts.consumerKey || typeof opts.consumerKey !== 'string') {
throw new Error('Invalid or missing `consumerKey` option');
}
if (!opts.consumerSecret || typeof opts.consumerSecret !== 'string') {
throw new Error('Invalid or missing `consumerSecret` option');
}
if (!opts.callbackUrl || typeof opts.callbackUrl !== 'string') {
throw new Error('Invalid or missing `callbackUrl` option');
}
this.consumerKey = opts.consumerKey;
this.consumerSecret = opts.consumerSecret;
this.callbackUrl = opts.callbackUrl;
this._oauth = OAuth({
consumer: {
key: this.consumerKey,
secret: this.consumerSecret
},
signature_method: 'HMAC-SHA1',
hash_function: (baseString, key) => {
return crypto.createHmac('sha1', key).update(baseString).digest('base64')
}
});
}
login () {
return new Promise((resolve, reject) => {
const requestData = {
url: TW_REQ_TOKEN_URL,
method: 'POST',
data: {
oauth_callback: this.callbackUrl
}
};
get.concat({
url: requestData.url,
method: requestData.method,
form: requestData.data,
headers: this._oauth.toHeader(this._oauth.authorize(requestData))
}, (err, res, data) => {
if (err) return reject(err);
const {
oauth_token: token,
oauth_token_secret: tokenSecret,
oauth_callback_confirmed: callbackConfirmed
} = querystring.parse(data.toString());
if (callbackConfirmed !== 'true') {
return reject(new Error('Missing `oauth_callback_confirmed` parameter in response'));
}
const url = `${TW_AUTH_URL}?${querystring.stringify({ oauth_token: token })}`;
resolve({ tokenSecret, url });
});
});
}
callback (params, tokenSecret) {
return new Promise((resolve, reject) => {
const {
oauth_token: token,
oauth_verifier: verifier
} = params;
if (typeof params.denied === 'string' && params.denied.length > 0) {
const err = new Error('User denied login permission');
err.code = 'USER_DENIED';
return reject(err);
}
if (typeof params.oauth_token !== 'string' || params.oauth_token.length === 0) {
return reject(new Error('Invalid or missing `oauth_token` parameter for login callback'));
}
if (typeof params.oauth_verifier !== 'string' || params.oauth_verifier.length === 0) {
return reject(new Error('Invalid or missing `oauth_verifier` parameter for login callback'));
}
if (typeof tokenSecret !== 'string' || tokenSecret.length === 0) {
return reject(new Error('Invalid or missing `tokenSecret` argument for login callback'));
}
const requestData = {
url: TW_ACCESS_TOKEN_URL,
method: 'POST',
data: {
oauth_token: token,
oauth_token_secret: tokenSecret,
oauth_verifier: verifier
}
};
get.concat({
url: requestData.url,
method: requestData.method,
form: requestData.data,
headers: this._oauth.toHeader(this._oauth.authorize(requestData))
}, (err, res, data) => {
if (err) return reject(err);
const {
oauth_token: userToken,
oauth_token_secret: userTokenSecret,
screen_name: userName,
user_id: userId
} = querystring.parse(data.toString());
resolve({
userName,
userId,
userToken,
userTokenSecret
});
});
});
}
userInfo (params) {
return new Promise((resolve, reject) => {
const {
userToken: token,
userTokenSecret: secret,
} = params;
if (typeof params.denied === 'string' && params.denied.length > 0) {
const err = new Error('User denied login permission');
err.code = 'USER_DENIED';
return reject(err);
}
if (typeof params.userToken !== 'string' || params.userToken.length === 0) {
return reject(new Error('Invalid or missing `oauth_token` parameter for login callback'));
}
if (typeof params.userTokenSecret !== 'string' || params.userTokenSecret.length === 0) {
return reject(new Error('Invalid or missing `oauth_verifier` parameter for login callback'));
}
const requestData = {
url: 'https://api.twitter.com/1.1/account/verify_credentials.json?skip_status=true&include_email=true&include_entities=false',
method: 'GET',
};
const tokenInfo = {
key: token,
secret,
};
const headers = this._oauth.toHeader(this._oauth.authorize(requestData, tokenInfo));
get.concat({
url: requestData.url,
method: requestData.method,
headers,
json: true,
}, (err, res, data) => {
if (err) return reject(err);
resolve(data);
});
});
}
}
module.exports = LoginWithTwitter;