Skip to content

add third party github login for future updates in vscode-leetcode #34

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

Merged
merged 5 commits into from
Dec 24, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Great thanks to leetcode.com, a really awesome website!

Read help first $ leetcode help
Login with your leetcode account $ leetcode user -l
Login with third party account--github $ leetcode user -g
Cookie login with cookie $ leetcode user -c
Browse all questions $ leetcode list
Choose one question $ leetcode show 1 -g -l cpp
Expand Down
22 changes: 22 additions & 0 deletions lib/commands/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ const cmd = {
default: false,
describe: 'cookieLogin'
})
.option('g', {
alias: 'github',
type: 'boolean',
default: false,
describe: 'githubLogin'
})
.option('L', {
alias: 'logout',
type: 'boolean',
Expand All @@ -36,6 +42,7 @@ const cmd = {
.example(chalk.yellow('leetcode user'), 'Show current user')
.example(chalk.yellow('leetcode user -l'), 'User login')
.example(chalk.yellow('leetcode user -c'), 'User Cookie login')
.example(chalk.yellow('leetcode user -g'), 'User Github login')
.example(chalk.yellow('leetcode user -L'), 'User logout');
}
};
Expand Down Expand Up @@ -66,6 +73,21 @@ cmd.handler = function(argv) {
log.info('Successfully logout as', chalk.yellow(user.name));
else
log.fail('You are not login yet?');
} else if (argv.github) {
// github
prompt.colors = false;
prompt.message = '';
prompt.start();
prompt.get([
{name: 'login', required: true},
{name: 'pass', required: true, hidden: true}
], function(e, user) {
if (e) return log.fail(e)
core.githubLogin(user, function(e, user) {
if (e) return log.fail(e);
log.info('Successfully github login as', chalk.yellow(user.name));
});
});
} else if (argv.cookie) {
// session
prompt.colors = false;
Expand Down
2 changes: 2 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const DEFAULT_CONFIG = {
base: 'https://leetcode.com',
graphql: 'https://leetcode.com/graphql',
login: 'https://leetcode.com/accounts/login/',
// third part login base urls. TODO facebook linkin google
github_login: 'https://leetcode.com/accounts/github/login/?next=%2F',
problems: 'https://leetcode.com/api/problems/$category/',
problem: 'https://leetcode.com/problems/$slug/description/',
test: 'https://leetcode.com/problems/$slug/interpret_solution/',
Expand Down
83 changes: 66 additions & 17 deletions lib/plugins/leetcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ plugin.checkError = function(e, resp, expectedStatus) {

plugin.init = function() {
config.app = 'leetcode';
}
};

plugin.getProblems = function(cb) {
log.debug('running leetcode.getProblems');
Expand Down Expand Up @@ -95,7 +95,7 @@ plugin.getCategoryProblems = function(category, cb) {
}

const problems = json.stat_status_pairs
.filter(p => !p.stat.question__hide)
.filter((p) => !p.stat.question__hide)
.map(function(p) {
return {
state: p.status || 'None',
Expand Down Expand Up @@ -167,7 +167,7 @@ plugin.getProblem = function(problem, cb) {
problem.testable = q.enableRunCode;
problem.templateMeta = JSON.parse(q.metaData);
// @si-yao: seems below property is never used.
//problem.discuss = q.discussCategoryId;
// problem.discuss = q.discussCategoryId;

return cb(null, problem);
});
Expand Down Expand Up @@ -254,9 +254,9 @@ function formatResult(result) {
};

x.error = _.chain(result)
.pick((v, k) => /_error$/.test(k) && v.length > 0)
.values()
.value();
.pick((v, k) => /_error$/.test(k) && v.length > 0)
.values()
.value();

if (/[runcode|interpret].*/.test(result.submission_id)) {
// It's testing
Expand Down Expand Up @@ -374,8 +374,8 @@ plugin.starProblem = function(problem, starred, cb) {
};
} else {
opts.url = config.sys.urls.favorite_delete
.replace('$hash', user.hash)
.replace('$id', problem.id);
.replace('$hash', user.hash)
.replace('$id', problem.id);
opts.method = 'DELETE';
}

Expand Down Expand Up @@ -508,7 +508,7 @@ plugin.signin = function(user, cb) {
plugin.getUser = function(user, cb) {
plugin.getFavorites(function(e, favorites) {
if (!e) {
const f = favorites.favorites.private_favorites.find(f => f.name === 'Favorite');
const f = favorites.favorites.private_favorites.find((f) => f.name === 'Favorite');
if (f) {
user.hash = f.id_hash;
user.name = favorites.user_name;
Expand Down Expand Up @@ -538,19 +538,68 @@ plugin.login = function(user, cb) {
});
};

plugin.cookieLogin = function(user, cb) {
// re pattern for cookie chrome or firefox
function parseCookie(cookie, cb) {
const SessionPattern = /LEETCODE_SESSION=(.+?)(;|$)/;
const csrfPattern = /csrftoken=(.+?)(;|$)/;
const reSessionResult = SessionPattern.exec(user.cookie);
const reCsrfResult = csrfPattern.exec(user.cookie);
const reSessionResult = SessionPattern.exec(cookie);
const reCsrfResult = csrfPattern.exec(cookie);
if (reSessionResult === null || reCsrfResult === null) {
return cb('invalid cookie?')
return cb('invalid cookie?');
}
user.sessionId = reSessionResult[1];
user.sessionCSRF = reCsrfResult[1];
return {
sessionId: reSessionResult[1],
sessionCSRF: reCsrfResult[1],
};
}

plugin.cookieLogin = function(user, cb) {
const cookieData = parseCookie(user.cookie, cb);
user.sessionId = cookieData.sessionId;
user.sessionCSRF = cookieData.sessionCSRF;
session.saveUser(user);
plugin.getUser(user, cb);
}
};

plugin.githubLogin = function(user, cb) {
const leetcodeUrl = config.sys.urls.github_login;
const _request = request.defaults({jar: true});
_request('https://github.com/login', function(e, resp, body) {
const authenticityToken = body.match(/name="authenticity_token" value="(.*?)"/);
if (authenticityToken === null) {
return cb('Get github token failed');
}
const options = {
url: 'https://github.com/session',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
followAllRedirects: true,
form: {
'login': user.login,
'password': user.pass,
'authenticity_token': authenticityToken[1],
'utf8': encodeURIComponent('✓'),
'commit': encodeURIComponent('Sign in')
},
};
_request(options, function(e, resp, body) {
if (resp.statusCode !== 200) {
return cb('Github login failed');
}
_request.get({url: leetcodeUrl}, function(e, resp, body) {
const redirectUri = resp.request.uri.href;
if (redirectUri !== 'https://leetcode.com/') {
return cb('Github login failed or github did not link to leetcode');
}
const cookieData = parseCookie(resp.request.headers.cookie, cb);
user.sessionId = cookieData.sessionId;
user.sessionCSRF = cookieData.sessionCSRF;
session.saveUser(user);
plugin.getUser(user, cb);
});
});
});
};

module.exports = plugin;