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
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
@@ -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
22 changes: 22 additions & 0 deletions lib/commands/user.js
Original file line number Diff line number Diff line change
@@ -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',
@@ -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');
}
};
@@ -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;
2 changes: 2 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -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/',
83 changes: 66 additions & 17 deletions lib/plugins/leetcode.js
Original file line number Diff line number Diff line change
@@ -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');
@@ -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',
@@ -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);
});
@@ -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
@@ -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';
}

@@ -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;
@@ -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;