Skip to content
This repository was archived by the owner on Feb 18, 2024. It is now read-only.

Remove username/password support; always use tokens #91

Merged
merged 1 commit into from
Jun 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 33 additions & 41 deletions github.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ catch(e) {}
var execGit = require('./exec-git');

function createRemoteStrings(auth, hostname) {
var authString = auth ? (encodeURIComponent(auth.username) + ':' + encodeURIComponent(auth.password) + '@') : '';
var authString = auth.username ? (encodeURIComponent(auth.username) + ':' + encodeURIComponent(auth.password) + '@') : '';
hostname = hostname || 'github.com';

this.remoteString = 'https://' + authString + hostname + '/';
this.authSuffix = auth.token ? '?access_token=' + auth.token : '';

if (hostname == 'github.com')
this.apiRemoteString = 'https://' + authString + 'api.github.com/';
Expand All @@ -44,10 +45,6 @@ function createRemoteStrings(auth, hostname) {
this.apiRemoteString = 'https://' + authString + hostname + '/api/v3/';
}

// avoid storing passwords as plain text in config
function encodeCredentials(auth) {
return new Buffer(auth.username + ':' + auth.password).toString('base64');
}
function decodeCredentials(str) {
var auth = new Buffer(str, 'base64').toString('utf8').split(':');

Expand Down Expand Up @@ -80,6 +77,10 @@ function readNetrc(hostname) {
}
}

function isGithubToken(token) {
return token.match(/[0-9a-f]{40}/);
}

var GithubLocation = function(options, ui) {

// ensure git is installed
Expand All @@ -97,19 +98,15 @@ var GithubLocation = function(options, ui) {
this.versionString = options.versionString + '.1';

// Give the environment precedence over options object
if(process.env.JSPM_GITHUB_AUTH_TOKEN) {
options.auth = process.env.JSPM_GITHUB_AUTH_TOKEN;
} else if (options.username && !options.auth) {
options.auth = encodeCredentials(options);
// NB deprecate old auth eventually
// delete options.username;
// delete options.password;
}
var auth = process.env.JSPM_GITHUB_AUTH_TOKEN || options.auth;

if (typeof options.auth == 'string') {
this.auth = decodeCredentials(options.auth);
}
else {
if (auth) {
if (isGithubToken(auth)) {
this.auth = { token: auth };
} else {
this.auth = decodeCredentials(auth);
}
} else {
this.auth = readNetrc(options.hostname);
}

Expand Down Expand Up @@ -147,7 +144,7 @@ var GithubLocation = function(options, ui) {

this.remote = options.remote;

createRemoteStrings.call(this, this.auth, options.hostname);
createRemoteStrings.call(this, this.auth || {}, options.hostname);
};

function clearDir(dir) {
Expand Down Expand Up @@ -198,20 +195,14 @@ function configureCredentials(config, ui) {

return Promise.resolve()
.then(function() {
ui.log('info', 'If using two-factor authentication or to avoid using your password you can generate an access token at %https://' + (config.hostname || 'github.com') + '/settings/tokens%. Ensure it has `public_repo` scope access.');
return ui.input('Enter your GitHub username');
})
.then(function(username) {
auth.username = username;
if (auth.username)
return ui.input('Enter your GitHub password or access token', null, true);
ui.log('info', 'You can generate an access token at %https://' + (config.hostname || 'github.com') + '/settings/tokens%.');
return ui.input('Enter your GitHub access token');
})
.then(function(password) {
auth.password = password;
if (!auth.username)
return false;

return ui.confirm('Would you like to test these credentials?', true);
.then(function(token) {
auth.token = token;
if (auth.token) {
return ui.confirm('Would you like to test these credentials?', true);
}
})
.then(function(test) {
if (!test)
Expand All @@ -223,7 +214,7 @@ function configureCredentials(config, ui) {
createRemoteStrings.call(remotes, auth, config.hostname);

return asp(request)({
uri: remotes.apiRemoteString + 'user',
uri: remotes.apiRemoteString + 'user' + remotes.authSuffix,
headers: {
'User-Agent': 'jspm',
'Accept': 'application/vnd.github.v3+json'
Expand All @@ -234,7 +225,7 @@ function configureCredentials(config, ui) {
})
.then(function(res) {
if (res.statusCode == 401) {
ui.log('warn', 'Provided GitHub credentials are not authorized, try re-entering your password or access token.');
ui.log('warn', 'Provided GitHub credentials are not authorized, try re-entering your access token.');
}
else if (res.statusCode != 200) {
ui.log('warn', 'Invalid response code, %' + res.statusCode + '%');
Expand All @@ -253,10 +244,10 @@ function configureCredentials(config, ui) {
.then(function(redo) {
if (redo)
return configureCredentials(config, ui);
return encodeCredentials(auth);
return auth.token;
});
else if (auth.username)
return encodeCredentials(auth);
else if (auth.token)
return auth.token;
else
return null;
});
Expand Down Expand Up @@ -302,14 +293,15 @@ GithubLocation.prototype = {
locate: function(repo) {
var self = this;
var remoteString = this.remoteString;
var authSuffix = this.authSuffix;

if (repo.split('/').length !== 2)
throw "GitHub packages must be of the form `owner/repo`.";

// request the repo to check that it isn't a redirect
return new Promise(function(resolve, reject) {
request(extend({
uri: remoteString + repo,
uri: remoteString + repo + authSuffix,
headers: {
'User-Agent': 'jspm'
},
Expand Down Expand Up @@ -352,8 +344,7 @@ GithubLocation.prototype = {
execGit('ls-remote ' + remoteString.replace(/(['"()])/g, '\\\$1') + repo + '.git refs/tags/* refs/heads/*', execOpt, function(err, stdout, stderr) {
if (err) {
if (err.toString().indexOf('not found') == -1) {
// dont show plain text passwords in error
var error = new Error(stderr.toString().replace(remoteString, ''));
var error = new Error(stderr);
error.hideStack = true;
error.retriable = true;
reject(error);
Expand Down Expand Up @@ -410,7 +401,7 @@ GithubLocation.prototype = {
var ui = this.ui;

return asp(request)({
uri: this.apiRemoteString + 'repos/' + repo + '/contents/package.json',
uri: this.apiRemoteString + 'repos/' + repo + '/contents/package.json' + this.authSuffix,
headers: {
'User-Agent': 'jspm',
'Accept': 'application/vnd.github.v3.raw'
Expand Down Expand Up @@ -546,13 +537,14 @@ GithubLocation.prototype = {
var execOpt = this.execOpt;
var max_repo_size = this.max_repo_size;
var remoteString = this.remoteString;
var authSuffix = this.authSuffix;

var self = this;

// Download from the git archive
return new Promise(function(resolve, reject) {
request({
uri: remoteString + repo + '/archive/' + version + '.tar.gz',
uri: remoteString + repo + '/archive/' + version + '.tar.gz' + authSuffix,
headers: { 'accept': 'application/octet-stream' },
strictSSL: self.defaultRequestOptions.strictSSL
})
Expand Down
4 changes: 2 additions & 2 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ github = new github({
baseDir: '.',
log: true,
tmpDir: '.',
username: '',
password: ''
auth: '',
token: ''
});

github.lookup('angular/bower-angular')
Expand Down