Finishing merge

This commit is contained in:
ekatek
2014-03-04 22:29:01 -08:00
4 changed files with 123 additions and 86 deletions

View File

@@ -408,15 +408,10 @@ var fetchGalaxyOAuthInfo = function (galaxyName, timeout) {
}
};
// XXX De-dup with logInToGalaxy
// XXX make args options
var oauthFlow = function (conn, clientId, redirectUri,
domain, sessionType) {
var crypto = require('crypto');
var credentialToken = crypto.randomBytes(16).toString('hex');
var sendAuthorizeRequest = function (clientId, redirectUri, state) {
var authCodeUrl = config.getOauthUrl() + "/authorize?" +
querystring.stringify({
state: credentialToken,
state: state,
response_type: "code",
client_id: clientId,
redirect_uri: redirectUri
@@ -450,9 +445,36 @@ var oauthFlow = function (conn, clientId, redirectUri,
return { error: 'access-denied' };
}
return { location: response.headers.location };
};
// Do an OAuth flow with the Meteor developer accounts server to log in
// to an OAuth client. `conn` is expected to be a DDP connection to the
// OAuth client app. Options are:
// - clientId: OAuth client id parameter
// - redirectUri: OAuth redirect_uri parameter
// - domain: the domain for saving the received login token on success
// in the Meteor session file
// - sessionType: the value of the 'type' field for the session saved
// in the Meteor session file on success
// All options are required.
var oauthFlow = function (conn, options) {
var crypto = require('crypto');
var credentialToken = crypto.randomBytes(16).toString('hex');
var authorizeResult = sendAuthorizeRequest(
options.clientId,
options.redirectUri,
credentialToken
);
if (authorizeResult.error) {
return authorizeResult;
}
try {
var redirectResult = httpHelpers.request({
url: response.headers.location,
url: authorizeResult.location,
method: 'GET',
strictSSL: true
});
@@ -460,7 +482,7 @@ var oauthFlow = function (conn, clientId, redirectUri,
return { error: 'no-package-server' };
}
response = redirectResult.response;
var response = redirectResult.response;
// 'access-denied' isn't exactly right because it's possible that the server
// went down since our last request, but close enough.
@@ -475,14 +497,14 @@ var oauthFlow = function (conn, clientId, redirectUri,
if (loginResult.token && loginResult.id) {
var data = readSessionData();
var session = getSession(data, domain);
ensureSessionType(session, sessionType);
var session = getSession(data, options.domain);
ensureSessionType(session, options.sessionType);
session.token = loginResult.token;
writeSessionData(data);
return 0;
return true;
} else {
process.stderr.write('Login failed');
return 1;
return false;
}
};
@@ -501,52 +523,32 @@ var logInToGalaxy = function (galaxyName) {
var galaxyClientId = oauthInfo.oauthClientId;
var galaxyRedirect = oauthInfo.redirectUri;
// If the redirect URI is not in the DNS namespace that belongs to the
// Galaxy, then something is wrong.
if (url.parse(galaxyRedirect).hostname !== galaxyName) {
// XXX It's more like 'bad-galaxy' than 'no-galaxy'.
return { error: 'no-galaxy' };
}
// Ask the accounts server for an authorization code.
var crypto = require('crypto');
var session = crypto.randomBytes(16).toString('hex');
var stateInfo = { session: session };
var authCodeUrl = config.getOauthUrl() + "/authorize?" +
querystring.stringify({
state: encodeURIComponent(JSON.stringify(stateInfo)),
response_type: "code",
client_id: galaxyClientId,
redirect_uri: galaxyRedirect
});
var authorizeResult = sendAuthorizeRequest(
galaxyClientId,
galaxyRedirect,
encodeURIComponent(JSON.stringify(stateInfo))
);
// It's very important that we don't have request follow the
// redirect for us, but instead issue the second request ourselves,
// since request would pass our credentials along to the redirected
// URL. See comments in http-helpers.js.
try {
var codeResult = httpHelpers.request({
url: authCodeUrl,
method: 'POST',
strictSSL: true,
useAuthHeader: true
});
} catch (e) {
return { error: 'no-account-server' };
}
var response = codeResult.response;
if (response.statusCode !== 302 || ! response.headers.location) {
return { error: 'access-denied' };
}
if (url.parse(response.headers.location).hostname !== galaxyName) {
// If we didn't get an immediate redirect to the redirectUri
// (which had better be in DNS namespace that belongs to the
// Galaxy) then presumably the oauth server is trying to interact
// with us (make us log in, authorize the client, or something
// like that). We're not a web browser so we can't participate in
// such things.
return { error: 'access-denied' };
if (authorizeResult.error) {
return authorizeResult;
}
// Ask the galaxy to log us in with our auth code.
try {
var galaxyResult = httpHelpers.request({
url: response.headers.location,
url: authorizeResult.location,
method: 'GET',
strictSSL: true,
headers: {
@@ -559,7 +561,7 @@ var logInToGalaxy = function (galaxyName) {
} catch (e) {
return { error: (body && body.error) || 'no-galaxy' };
}
response = galaxyResult.response;
var response = galaxyResult.response;
// 'access-denied' isn't exactly right because it's possible that the galaxy
// went down since our last request, but close enough.

View File

@@ -1306,7 +1306,6 @@ main.registerCommand({
minArgs: 0,
maxArgs: 0,
options: {
versionString: { type: String, short: "v", required: true },
// XXX A temporary option to create the package, until we sync
// package metadata to the client.
create: { type: Boolean }
@@ -1318,11 +1317,16 @@ main.registerCommand({
));
var name = pkg.name;
var version = options.version;
var version = pkg.metadata.version;
if (! version) {
process.stderr.write('Package must have a version\n');
return 1;
}
var conn = packageClient.loggedInPackagesConnection();
if (! conn) {
process.stderr.write('Publish failed');
process.stderr.write('Publish failed\n');
return 1;
}
@@ -1338,7 +1342,7 @@ main.registerCommand({
process.stdout.write('Creating package version...\n');
var uploadInfo = conn.call('createPackageVersion', {
packageName: pkg.name,
version: options.versionString,
version: version,
description: pkg.metadata.summary
});
@@ -1385,7 +1389,7 @@ main.registerCommand({
conn.call('publishPackageVersion', uploadInfo.uploadToken, tarballHash);
conn.close();
process.stdout.write('Published ' + pkg.name +
', version ' + options.versionString);
', version ' + version);
process.stdout.write('\nDone!\n');
return 0;

View File

@@ -23,7 +23,6 @@ var openPackageServerConnection = function () {
});
};
var loadLocalPackageData = function () {
var finalCollections = {};
// var packages = ["versions", "packages", "builds"];
@@ -110,55 +109,84 @@ loadPackageData = function() {
}
// XXX onReconnect
// Returns a logged-in DDP connection to the package server, or null if
// we cannot log in.
// XXX needs a timeout
exports.loggedInPackagesConnection = function () {
// Make sure that we are logged in with Meteor Accounts so that we can
// do an OAuth flow.
if (! auth.isLoggedIn()) {
auth.doUsernamePasswordLogin({ retry: true });
}
var conn = openPackageServerConnection();
var serviceConfigurations = new (getLoadedPackages()['meteor'].
Meteor.Collection)('meteor_accounts_loginServiceConfiguration', {
connection: conn
});
var fut = new Future();
var serviceConfigurationsSub = conn.subscribe(
'meteor.loginServiceConfiguration',
fut.resolver()
var setUpOnReconnect = function () {
conn.onReconnect = function () {
conn.apply('login', [{
resume: auth.getSessionToken(config.getPackageServerDomain())
}], { wait: true }, function () { });
};
};
// Subscribe to the package server's service configurations so that we
// can get the OAuth client ID to kick off the OAuth flow.
var serviceConfigurations = new (getLoadedPackages().meteor.Meteor.Collection)(
'meteor_accounts_loginServiceConfiguration',
{ connection: conn }
);
fut.wait();
var serviceConfigurationsSub = conn.
_subscribeAndWait('meteor.loginServiceConfiguration');
var accountsConfiguration = serviceConfigurations.findOne({
service: 'meteor-developer'
});
if (! accountsConfiguration) {
var cleanUp = function () {
serviceConfigurationsSub.stop();
conn.close();
};
if (! accountsConfiguration || ! accountsConfiguration.clientId) {
cleanUp();
return null;
}
var clientId = accountsConfiguration.clientId;
var loginResult;
if (! auth.getSessionToken(config.getPackageServerDomain())) {
// Since we passed retry: true, we shouldn't ever get to this point
// unless we are now logged in with the accounts server.
var redirectUri = config.getPackageServerUrl() +
'/_oauth/meteor-developer?close';
loginResult = auth.oauthFlow(conn, clientId, redirectUri,
config.getPackageServerDomain(),
'package-server');
if (! loginResult) {
conn.close();
return null;
}
} else {
// Try to log in with an existing login token, if we have one.
var existingToken = auth.getSessionToken(config.getPackageServerDomain());
if (existingToken) {
loginResult = conn.apply('login', [{
resume: auth.getSessionToken(config.getPackageServerDomain())
resume: existingToken
}], { wait: true });
if (! loginResult || ! loginResult.token || ! loginResult.id) {
conn.close();
return null;
if (loginResult && loginResult.token && loginResult.id) {
// Success!
setUpOnReconnect();
return conn;
}
}
return conn;
// Either we didn't have an existing token, or it didn't work. Do an
// OAuth flow to log in.
var redirectUri = config.getPackageServerUrl() +
'/_oauth/meteor-developer?close';
loginResult = auth.oauthFlow(conn, {
clientId: clientId,
redirectUri: redirectUri,
domain: config.getPackageServerDomain(),
sessionType: 'package-server'
});
if (loginResult && ! loginResult.error) {
setUpOnReconnect();
return conn;
} else {
process.stderr.write('Error logging in to package server: ' +
loginResult.error + '\n');
cleanUp();
return null;
}
};

View File

@@ -840,7 +840,7 @@ var Package = function (library, packageDirectoryForBuildInfo) {
// dependencies
self.library = library;
// Package metadata. Keys are 'summary' and 'internal'.
// Package metadata. Keys are 'summary', 'internal', 'version'.
self.metadata = {};
// Available editions/subpackages ("slices") of this package. Array
@@ -1190,6 +1190,7 @@ _.extend(Package.prototype, {
// Set package metadata. Options:
// - summary: for 'meteor list'
// - internal: if true, hide in list
// - version: package version string (semver)
// There used to be a third option documented here,
// 'environments', but it was never implemented and no package
// ever used it.
@@ -1940,7 +1941,8 @@ _.extend(Package.prototype, {
self.name = name;
self.metadata = {
summary: mainJson.summary,
internal: mainJson.internal
internal: mainJson.internal,
version: mainJson.version
};
self.defaultSlices = mainJson.defaultSlices;
self.testSlices = mainJson.testSlices;
@@ -2121,6 +2123,7 @@ _.extend(Package.prototype, {
format: "unipackage-pre1",
summary: self.metadata.summary,
internal: self.metadata.internal,
version: self.metadata.version,
slices: [],
defaultSlices: self.defaultSlices,
testSlices: self.testSlices,