Skip to content

Commit 81616fe

Browse files
committed
Added missing plugins from leetcode-tools/leetcode-cli-plugins
Signed-off-by: Vincent Zhou <fireflysuccess@gmail.com>
1 parent cd5d4ef commit 81616fe

File tree

6 files changed

+970
-0
lines changed

6 files changed

+970
-0
lines changed

lib/plugins/cookie.chrome.js

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
var path = require('path');
2+
3+
var log = require('../log');
4+
var Plugin = require('../plugin');
5+
var Queue = require('../queue');
6+
var session = require('../session');
7+
8+
// [Usage]
9+
//
10+
// https://github.com/skygragon/leetcode-cli-plugins/blob/master/docs/cookie.chrome.md
11+
//
12+
var plugin = new Plugin(13, 'cookie.chrome', '2018.11.18',
13+
'Plugin to reuse Chrome\'s leetcode cookie.',
14+
['ffi:win32', 'keytar:darwin', 'ref:win32', 'ref-struct:win32', 'sqlite3']);
15+
16+
plugin.help = function() {
17+
switch (process.platform) {
18+
case 'darwin':
19+
break;
20+
case 'linux':
21+
log.warn('To complete the install: sudo apt install libsecret-tools');
22+
break;
23+
case 'win32':
24+
break;
25+
}
26+
};
27+
28+
var Chrome = {};
29+
30+
var ChromeMAC = {
31+
getDBPath: function() {
32+
return `${process.env.HOME}/Library/Application Support/Google/Chrome/${this.profile}/Cookies`;
33+
},
34+
iterations: 1003,
35+
getPassword: function(cb) {
36+
var keytar = require('keytar');
37+
keytar.getPassword('Chrome Safe Storage', 'Chrome').then(cb);
38+
}
39+
};
40+
41+
var ChromeLinux = {
42+
getDBPath: function() {
43+
return `${process.env.HOME}/.config/google-chrome/${this.profile}/Cookies`;
44+
},
45+
iterations: 1,
46+
getPassword: function(cb) {
47+
// FIXME: keytar failed to read gnome-keyring on ubuntu??
48+
var cmd = 'secret-tool lookup application chrome';
49+
var password = require('child_process').execSync(cmd).toString();
50+
return cb(password);
51+
}
52+
};
53+
54+
var ChromeWindows = {
55+
getDBPath: function() {
56+
return path.resolve(process.env.APPDATA || '', `../Local/Google/Chrome/User Data/${this.profile}/Cookies`);
57+
},
58+
getPassword: function(cb) { cb(); }
59+
};
60+
61+
Object.setPrototypeOf(ChromeMAC, Chrome);
62+
Object.setPrototypeOf(ChromeLinux, Chrome);
63+
Object.setPrototypeOf(ChromeWindows, Chrome);
64+
65+
Chrome.getInstance = function() {
66+
switch (process.platform) {
67+
case 'darwin': return ChromeMAC;
68+
case 'linux': return ChromeLinux;
69+
case 'win32': return ChromeWindows;
70+
}
71+
};
72+
var my = Chrome.getInstance();
73+
74+
ChromeWindows.decodeCookie = function(cookie, cb) {
75+
var ref = require('ref');
76+
var ffi = require('ffi');
77+
var Struct = require('ref-struct');
78+
79+
var DATA_BLOB = Struct({
80+
cbData: ref.types.uint32,
81+
pbData: ref.refType(ref.types.byte)
82+
});
83+
var PDATA_BLOB = new ref.refType(DATA_BLOB);
84+
var Crypto = new ffi.Library('Crypt32', {
85+
'CryptUnprotectData': ['bool', [PDATA_BLOB, 'string', 'string', 'void *', 'string', 'int', PDATA_BLOB]]
86+
});
87+
88+
var inBlob = new DATA_BLOB();
89+
inBlob.pbData = cookie;
90+
inBlob.cbData = cookie.length;
91+
var outBlob = ref.alloc(DATA_BLOB);
92+
93+
Crypto.CryptUnprotectData(inBlob.ref(), null, null, null, null, 0, outBlob);
94+
var outDeref = outBlob.deref();
95+
var buf = ref.reinterpret(outDeref.pbData, outDeref.cbData, 0);
96+
97+
return cb(null, buf.toString('utf8'));
98+
};
99+
100+
Chrome.decodeCookie = function(cookie, cb) {
101+
var crypto = require('crypto');
102+
crypto.pbkdf2(my.password, 'saltysalt', my.iterations, 16, 'sha1', function(e, key) {
103+
if (e) return cb(e);
104+
105+
var iv = new Buffer(' '.repeat(16));
106+
var decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
107+
decipher.setAutoPadding(false);
108+
109+
var buf = decipher.update(cookie.slice(3)); // remove prefix "v10" or "v11"
110+
var final = decipher.final();
111+
final.copy(buf, buf.length - 1);
112+
113+
var padding = buf[buf.length - 1];
114+
if (padding) buf = buf.slice(0, buf.length - padding);
115+
116+
return cb(null, buf.toString('utf8'));
117+
});
118+
};
119+
120+
function doDecode(key, queue, cb) {
121+
var ctx = queue.ctx;
122+
var cookie = ctx[key];
123+
if (!cookie) return cb('Not found cookie: ' + key);
124+
125+
my.decodeCookie(cookie, function(e, cookie) {
126+
ctx[key] = cookie;
127+
return cb();
128+
});
129+
}
130+
131+
Chrome.getCookies = function(cb) {
132+
var sqlite3 = require('sqlite3');
133+
var db = new sqlite3.Database(my.getDBPath());
134+
db.on('error', cb);
135+
var KEYS = ['csrftoken', 'LEETCODE_SESSION'];
136+
137+
db.serialize(function() {
138+
var cookies = {};
139+
var sql = 'select name, encrypted_value from cookies where host_key like "%leetcode.com"';
140+
db.each(sql, function(e, x) {
141+
if (e) return cb(e);
142+
if (KEYS.indexOf(x.name) < 0) return;
143+
cookies[x.name] = x.encrypted_value;
144+
});
145+
146+
db.close(function() {
147+
my.getPassword(function(password) {
148+
my.password = password;
149+
var q = new Queue(KEYS, cookies, doDecode);
150+
q.run(null, cb);
151+
});
152+
});
153+
});
154+
};
155+
156+
plugin.signin = function(user, cb) {
157+
log.debug('running cookie.chrome.signin');
158+
log.debug('try to copy leetcode cookies from chrome ...');
159+
160+
my.profile = plugin.config.profile || 'Default';
161+
my.getCookies(function(e, cookies) {
162+
if (e) {
163+
log.error(`Failed to copy cookies from profile "${my.profile}"`);
164+
log.error(e);
165+
return plugin.next.signin(user, cb);
166+
}
167+
168+
log.debug('Successfully copied leetcode cookies!');
169+
user.sessionId = cookies.LEETCODE_SESSION;
170+
user.sessionCSRF = cookies.csrftoken;
171+
session.saveUser(user);
172+
return cb(null, user);
173+
});
174+
};
175+
176+
plugin.login = function(user, cb) {
177+
log.debug('running cookie.chrome.login');
178+
plugin.signin(user, function(e, user) {
179+
if (e) return cb(e);
180+
plugin.getUser(user, cb);
181+
});
182+
};
183+
184+
module.exports = plugin;

lib/plugins/cookie.firefox.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
var log = require('../log');
2+
var Plugin = require('../plugin');
3+
var session = require('../session');
4+
5+
// [Usage]
6+
//
7+
// https://github.com/skygragon/leetcode-cli-plugins/blob/master/docs/cookie.firefox.md
8+
//
9+
var plugin = new Plugin(13, 'cookie.firefox', '2018.11.19',
10+
'Plugin to reuse firefox\'s leetcode cookie.',
11+
['glob', 'sqlite3']);
12+
13+
function getCookieFile(cb) {
14+
var f;
15+
switch (process.platform) {
16+
case 'darwin':
17+
f = process.env.HOME + '/Library/Application Support/Firefox/Profiles/*.default*/cookies.sqlite';
18+
break;
19+
case 'linux':
20+
f = process.env.HOME + '/.mozilla/firefox/*.default*/cookies.sqlite';
21+
break;
22+
case 'win32':
23+
f = (process.env.APPDATA || '') + '/Mozilla/Firefox/Profiles/*.default*/cookies.sqlite';
24+
break;
25+
}
26+
require('glob')(f, {}, cb);
27+
}
28+
29+
function getCookies(cb) {
30+
getCookieFile(function(e, files) {
31+
if (e || files.length === 0) return cb('Not found cookie file!');
32+
33+
var sqlite3 = require('sqlite3');
34+
var db = new sqlite3.Database(files[0]);
35+
var KEYS = ['csrftoken', 'LEETCODE_SESSION'];
36+
37+
db.serialize(function() {
38+
var cookies = {};
39+
var sql = 'select name, value from moz_cookies where host like "%leetcode.com"';
40+
db.each(sql, function(e, x) {
41+
if (e) return cb(e);
42+
if (KEYS.indexOf(x.name) < 0) return;
43+
cookies[x.name] = x.value;
44+
});
45+
46+
db.close(function() {
47+
return cb(null, cookies);
48+
});
49+
});
50+
});
51+
}
52+
53+
plugin.signin = function(user, cb) {
54+
log.debug('running cookie.firefox.signin');
55+
log.debug('try to copy leetcode cookies from firefox ...');
56+
getCookies(function(e, cookies) {
57+
if (e) {
58+
log.error('Failed to copy cookies: ' + e);
59+
return plugin.next.signin(user, cb);
60+
}
61+
62+
if (!cookies.LEETCODE_SESSION || !cookies.csrftoken) {
63+
log.error('Got invalid cookies: ' + JSON.stringify(cookies));
64+
return plugin.next.signin(user, cb);
65+
}
66+
67+
log.debug('Successfully copied leetcode cookies!');
68+
user.sessionId = cookies.LEETCODE_SESSION;
69+
user.sessionCSRF = cookies.csrftoken;
70+
session.saveUser(user);
71+
return cb(null, user);
72+
});
73+
};
74+
75+
plugin.login = function(user, cb) {
76+
log.debug('running cookie.firefox.login');
77+
plugin.signin(user, function(e, user) {
78+
if (e) return cb(e);
79+
plugin.getUser(user, cb);
80+
});
81+
};
82+
83+
module.exports = plugin;

lib/plugins/cpp.lint.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
var cp = require('child_process');
2+
3+
var log = require('../log');
4+
var Plugin = require('../plugin');
5+
6+
//
7+
// [Usage]
8+
//
9+
// https://github.com/skygragon/leetcode-cli-plugins/blob/master/docs/cpp.lint.md
10+
//
11+
var plugin = new Plugin(100, 'cpp.lint', '2017.07.27',
12+
'Plugin to do static code check on c++ code.');
13+
14+
var DEFAULT_FLAGS = [
15+
'-legal/copyright',
16+
'-build/include_what_you_use'
17+
];
18+
19+
plugin.testProblem = function(problem, cb) {
20+
// TODO: unify error handling
21+
if (!plugin.config.bin)
22+
return log.error('cpplint.py not configured correctly! (plugins:cpp.lint:bin)');
23+
24+
var flags = DEFAULT_FLAGS.concat(plugin.config.flags || []);
25+
26+
var cmd = [
27+
plugin.config.bin,
28+
'--filter=' + flags.join(','),
29+
problem.file
30+
].join(' ');
31+
32+
log.info('\nRunning cpplint ...');
33+
log.debug(cmd);
34+
log.info();
35+
36+
cp.exec(cmd, function(e, stdout, stderr) {
37+
if (e) {
38+
stderr.split('\n').forEach(function(line) {
39+
if (line.length > 0) log.error(line);
40+
});
41+
} else {
42+
plugin.next.testProblem(problem, cb);
43+
}
44+
});
45+
};
46+
47+
module.exports = plugin;

0 commit comments

Comments
 (0)