Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better solution for #15: simplify auth flow, more like Gatekeeper! #35

Merged
merged 1 commit into from
Jul 11, 2017
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
109 changes: 9 additions & 100 deletions public/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,22 @@ var currentGistView = document.getElementById('currentgist');
---------------------------------------------------- */

// If GitHub tempcode is available as a parameter, get access_token from server and log in!
if (getAllUrlParams().tempcode) {

let tempCode = getAllUrlParams().tempcode;
if ( window.location.href.match(/\?code=(.*)/) ) {
// Code for matching URL param from https://github.com/prose/gatekeeper
let tempCode = window.location.href.match(/\?code=(.*)/)[1];

// Remove parameter from URL, updating this entry in the client's browser history
history.replaceState(null, '', '/');

// TODO: show loading animation while waiting???
// TODO: refactor getAllUrlParams(), don't need it, just need ONE param!

// Send tempCode to server in exchange for GitHub access token sent via headers
getTokenFromServer(tempCode)
.then(function(access_token){

// Save the access token as a global variable for now
// Send tempCode to server in exchange for GitHub access token
get('/github-auth?code=' + tempCode).then(function(access_token){
// Save to local state
currentAccessToken = access_token;

// Authenticate with GitHub!
getJSON('https://api.github.com/user?access_token=' + currentAccessToken)
.then(loginUser).catch(handleError);

}, handleError).catch(handleError);
// Get user data
return getJSON('https://api.github.com/user?access_token=' + currentAccessToken);
}).then(loginUser).catch(handleError);

// Otherwise, if user has not yet started the login process,
} else {
Expand Down Expand Up @@ -609,27 +603,6 @@ function get(url) {
});
}

function getTokenFromServer(tempCode) {
return new Promise(function(succeed, fail) {
var req = new XMLHttpRequest();
req.open("GET", '/github-token', true);

// Set header:
req.setRequestHeader('GitHub-Temp-Code', tempCode);

req.addEventListener("load", function() {
if (req.status < 400)
succeed(req.getResponseHeader('GitHub-Token'));
else
fail(new Error("Request failed: " + req.statusText));
});
req.addEventListener("error", function() {
fail(new Error("Network error"));
});
req.send(null);
});
}

// Returns a promise for a POST request, similar to get() above
function postWithGitHubToken(url, postDataObject) {
return new Promise(function(succeed, fail) {
Expand Down Expand Up @@ -666,70 +639,6 @@ function handleError(error) {
console.log("Error: " + error);
};

// Returns an object containing URL parameters
// via https://www.sitepoint.com/get-url-parameters-with-javascript/
function getAllUrlParams(url) {

// get query string from url (optional) or window
var queryString = url ? url.split('?')[1] : window.location.search.slice(1);

// we'll store the parameters here
var obj = {};

// if query string exists
if (queryString) {

// stuff after # is not part of query string, so get rid of it
queryString = queryString.split('#')[0];

// split our query string into its component parts
var arr = queryString.split('&');

for (var i=0; i<arr.length; i++) {
// separate the keys and the values
var a = arr[i].split('=');

// in case params look like: list[]=thing1&list[]=thing2
var paramNum = undefined;
var paramName = a[0].replace(/\[\d*\]/, function(v) {
paramNum = v.slice(1,-1);
return '';
});

// set parameter value (use 'true' if empty)
var paramValue = typeof(a[1])==='undefined' ? true : a[1];

// (optional) keep case consistent
paramName = paramName.toLowerCase();
paramValue = paramValue.toLowerCase();

// if parameter name already exists
if (obj[paramName]) {
// convert value to array (if still string)
if (typeof obj[paramName] === 'string') {
obj[paramName] = [obj[paramName]];
}
// if no array index number specified...
if (typeof paramNum === 'undefined') {
// put the value on the end of the array
obj[paramName].push(paramValue);
}
// if array index number specified...
else {
// put the value at that index number
obj[paramName][paramNum] = paramValue;
}
}
// if param name doesn't exist yet, set it
else {
obj[paramName] = paramValue;
}
}
}

return obj;
}

function changeTurn() {
gameState.turnIndex = (gameState.turnIndex + 1) % gameState.players.length;
}
Expand Down
32 changes: 3 additions & 29 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ var port = process.env.PORT || 8000; // Set the default port number to 8000, or
// Use Express to serve everything in the "public" folder as static files
app.use(express.static('public'));

// Save table of temp codes and access tokens, for sending access tokens to the corresponding clients via headers
let clientTokens = {};

// Pass GITHUB_CLIENT_ID to client when requested (using AJAX for now)
// TODO (later): mess around with templating engines and Express .render()?
app.get('/github-client', function (req, res) {
console.log('Request received for /github-client route. Sending response: GITHUB_CLIENT_ID');
res.end(process.env.GITHUB_CLIENT_ID);
});

// Handle GitHub authentication at this route, then redirect to homepage
// Handle GitHub authentication at this route, then pass token back to client
app.get('/github-auth', authenticateUser);

function authenticateUser (req, res) {
Expand All @@ -47,42 +44,19 @@ function authenticateUser (req, res) {
githubResponseBody += chunk;
});
response.on('end', function() {
//console.log('\n*****done receiving response data:\n' + githubResponseBody + '\n');

// TODO (later): check the scopes, because users can authorize less than what my app requested!

// Save received access token to clientTokens to keep it associated with this client
clientTokens[req.query.code] = JSON.parse(githubResponseBody).access_token;

// Redirect to home page again, with the temp code as a URL param
// TODO (later): can I use server-side rendering to accomplish this also???
res.redirect('/?tempcode=' + req.query.code);
// Send GitHub access token back to client
res.end( JSON.parse(githubResponseBody).access_token );

});
});

request.write(postRequestBody);
request.end();

}

// Pass GitHub access token to corresponding client, if it matches client's temp code
app.get('/github-token', function (req, res) {

let tempCode = req.header('GitHub-Temp-Code');

console.log('Request received for /github-token route for temp code: ' + tempCode);

if ( clientTokens.hasOwnProperty(tempCode) ) {
console.log('\t Temp code MATCHES! Sending access token in response header!');
res.header('GitHub-Token', clientTokens[tempCode]);
}
res.end(); // Double check: can I use res.end() with no body?

console.log("\nclientTokens:\n");
console.log(clientTokens);
});

// Activate the server and listen on our specified port number
server.listen(port, function() {
// Display this message in the server console once the server is active
Expand Down