init
這個提交存在於:
當前提交
a75e5e12a9
2
.gitignore
vendored
一般檔案
2
.gitignore
vendored
一般檔案
|
@ -0,0 +1,2 @@
|
|||
login
|
||||
node_modules/
|
290
index.js
一般檔案
290
index.js
一般檔案
|
@ -0,0 +1,290 @@
|
|||
"use strict";
|
||||
|
||||
var Crawler = require("crawler");
|
||||
var path = require('path');
|
||||
var output = new(require('./src/console/output'));
|
||||
var input = new(require('./src/console/input'))(process);
|
||||
var pregMatch = require('./src/preg-match');
|
||||
var logger = require('./src/logger.js');
|
||||
var cookieBag = new(require('./src/cookie-bag.js'));
|
||||
|
||||
process.chdir(path.dirname(input.script));
|
||||
|
||||
var isDebugMode = input.has('debug');
|
||||
|
||||
if (!isDebugMode) {
|
||||
process.on('uncaughtException', function() {
|
||||
output.json({
|
||||
error: true,
|
||||
message: 'UncaughtException'
|
||||
});
|
||||
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
if (input.has('help')) {
|
||||
output.write([
|
||||
process.argv[0],
|
||||
process.argv[1],
|
||||
'[--crawler-debug]',
|
||||
'[--crawler-info]',
|
||||
'[--crawler-error]',
|
||||
].join(' '));
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var handlerCrawlerError = function(response, e) {
|
||||
output.json({
|
||||
error: true,
|
||||
message: {
|
||||
body: response.body,
|
||||
response: response,
|
||||
error: e,
|
||||
},
|
||||
}, true);
|
||||
}
|
||||
|
||||
var handlerCrawlerException = function(e, done) {
|
||||
if (isDebugMode) {
|
||||
throw e;
|
||||
} else {
|
||||
done();
|
||||
|
||||
return output.json({
|
||||
error: true,
|
||||
message: e
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var headers = function(crawler) {
|
||||
var datas = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 5.1; WOW64; rv:54.0) Gecko/20100101 Firefox/54.0',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'Accept-Language': 'fr,fr-FR;q=0.5',
|
||||
'Cookie': cookieBag.toString(),
|
||||
};
|
||||
|
||||
if (crawler.storage.hasOwnProperty('referer')) {
|
||||
datas['referer'] = crawler.storage.referer;
|
||||
}
|
||||
|
||||
return datas;
|
||||
}
|
||||
|
||||
var createCrawlerOptions = function(config) {
|
||||
var options = {
|
||||
maxConnections: 10,
|
||||
retries: 1,
|
||||
logger: logger,
|
||||
jQuery: false,
|
||||
};
|
||||
|
||||
config = config || {};
|
||||
|
||||
for (var i in config) {
|
||||
options[i] = config[i];
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
var createCrawler = function(options) {
|
||||
options = createCrawlerOptions(options || {});
|
||||
|
||||
if (!options.hasOwnProperty('callback') && options.hasOwnProperty('onSuccess')) {
|
||||
options.callback = function(error, response, done) {
|
||||
if (error) {
|
||||
handlerCrawlerError(response, error);
|
||||
} else {
|
||||
try {
|
||||
options.onSuccess(response, done);
|
||||
} catch (e) {
|
||||
return handlerCrawlerException(e, done);
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
var c = new Crawler(options);
|
||||
|
||||
c.storage = {};
|
||||
|
||||
c.runCrawl = function(url) {
|
||||
c.options.headers = headers(c);
|
||||
|
||||
return c.queue(url);
|
||||
};
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
try {
|
||||
var UrlRefreshRequester = createCrawler({
|
||||
onSuccess: function(response) {
|
||||
cookieBag.handleResponse(response);
|
||||
|
||||
var urlRefresh = pregMatch(/"urlRefresh":"([^"]+)"/, response.body)[1];
|
||||
|
||||
LoginFormRequester.runCrawl(urlRefresh);
|
||||
},
|
||||
});
|
||||
|
||||
var LoginFormRequester = createCrawler({
|
||||
onSuccess: function(response) {
|
||||
cookieBag.handleResponse(response);
|
||||
|
||||
var urlPost = pregMatch(/"urlPost":"([^"]+)"/, response.body)[1];
|
||||
var urlLogin = pregMatch(/"urlLogin":"([^"]+)"/, response.body)[1];
|
||||
|
||||
var data = {
|
||||
canary: pregMatch(/"canary":"([^"]+)"/, response.body)[1],
|
||||
ctx: pregMatch(/ctx=(.+)/, urlLogin)[1],
|
||||
hpgrequestid: pregMatch(/"sessionId":"([^"]+)"/, response.body)[1],
|
||||
flowToken: pregMatch(/"sFT":"([^"]+)"/, response.body)[1],
|
||||
f1: 'Suivant',
|
||||
NewUser: 1,
|
||||
CookieDisclosure: 1,
|
||||
fspost: 0,
|
||||
IsFidoSupported: 0,
|
||||
FoundMSAs: null,
|
||||
i2: 1,
|
||||
i13: 0,
|
||||
i17: '',
|
||||
i18: '',
|
||||
i19: 19471,
|
||||
ps: 2,
|
||||
psRNGCDefaultType: '',
|
||||
psRNGCEntropy: '',
|
||||
psRNGCSLK: '',
|
||||
PPSX: '',
|
||||
FoundMSAs: '',
|
||||
type: 11,
|
||||
LoginOptions: 3,
|
||||
Irt: '',
|
||||
IrtPartition: '',
|
||||
hisRegion: '',
|
||||
hisScaleUnit: '',
|
||||
loginfmt: process.env.MS_OFFICE365_LOGIN,
|
||||
login: process.env.MS_OFFICE365_LOGIN,
|
||||
passwd: process.env.MS_OFFICE365_PASSWORD,
|
||||
}
|
||||
|
||||
LoginRequester.options.form = data;
|
||||
|
||||
LoginRequester.runCrawl('https://login.microsoftonline.com' + urlPost)
|
||||
}
|
||||
});
|
||||
|
||||
var LoginRequester = createCrawler({
|
||||
method: 'POST',
|
||||
onSuccess: function(response) {
|
||||
cookieBag.handleResponse(response);
|
||||
|
||||
var data = {
|
||||
canary: pregMatch(/"canary":"([^"]+)"/, response.body)[1],
|
||||
ctx: pregMatch(/"sCtx":"([^"]+)"/, response.body)[1],
|
||||
hpgrequestid: pregMatch(/"sessionId":"([^"]+)"/, response.body)[1],
|
||||
flowToken: pregMatch(/"sFT":"([^"]+)"/, response.body)[1],
|
||||
LoginOptions: 1,
|
||||
}
|
||||
|
||||
KmsiRequester.options.form = data;
|
||||
|
||||
KmsiRequester.runCrawl('https://login.microsoftonline.com/kmsi');
|
||||
}
|
||||
});
|
||||
|
||||
var KmsiRequester = createCrawler({
|
||||
method: 'POST',
|
||||
jQuery: true,
|
||||
onSuccess: function(response) {
|
||||
cookieBag.handleResponse(response);
|
||||
|
||||
var data = {
|
||||
code: response.$('[name="code"]').val(),
|
||||
id_token: response.$('[name="id_token"]').val(),
|
||||
session_state: response.$('[name="session_state"]').val(),
|
||||
correlation_id: response.$('[name="correlation_id"]').val(),
|
||||
};
|
||||
|
||||
SiteRequester.options.form = data;
|
||||
SiteRequester.storage.referer = 'https://login.microsoftonline.com/kmsi';
|
||||
SiteRequester.runCrawl(process.env.MS_OFFICE365_SITE + '_forms/default.aspx');
|
||||
}
|
||||
});
|
||||
|
||||
var SiteRequester = createCrawler({
|
||||
method: 'POST',
|
||||
jQuery: true,
|
||||
onSuccess: function(response, done) {
|
||||
cookieBag.handleResponse(response);
|
||||
|
||||
if (SiteRequester.storage.hasOwnProperty('finish')) {
|
||||
output.json({
|
||||
rtFa: cookieBag.get('rtFa'),
|
||||
FedAuth: cookieBag.get('FedAuth'),
|
||||
}, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (SiteRequester.storage.hasOwnProperty('kmsi')) {
|
||||
delete SiteRequester.storage.kmsi;
|
||||
|
||||
SiteRequester.storage.finish = true;
|
||||
|
||||
return KmsiRequester.options.onSuccess(response);
|
||||
}
|
||||
|
||||
if (response.headers.hasOwnProperty('location')) {
|
||||
SiteRequester.options.method = 'GET';
|
||||
|
||||
var location = response.headers.location;
|
||||
|
||||
SiteRequester.runCrawl(location);
|
||||
} else {
|
||||
var urlPost = response.$('form').attr('action');
|
||||
|
||||
var data = {
|
||||
code: response.$('[name="code"]').val(),
|
||||
id_token: response.$('[name="id_token"]').val(),
|
||||
session_state: response.$('[name="session_state"]').val(),
|
||||
correlation_id: response.$('[name="correlation_id"]').val(),
|
||||
};
|
||||
|
||||
var params = urlPost.split('?')[1].split('&');
|
||||
|
||||
params.forEach(function(param) {
|
||||
var name = pregMatch(/([a-zA-Z0-9_-]+)=/, param)[1];
|
||||
var value = pregMatch(/=(.+)/, param)[1];
|
||||
|
||||
data[name] = decodeURIComponent(value);
|
||||
});
|
||||
|
||||
SiteRequester.options.method = 'POST';
|
||||
SiteRequester.options.form = data;
|
||||
SiteRequester.storage.referer = 'https://login.microsoftonline.com/kmsi';
|
||||
SiteRequester.storage.kmsi = true;
|
||||
SiteRequester.runCrawl(urlPost);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
UrlRefreshRequester.runCrawl(process.env.MS_OFFICE365_SITE);
|
||||
} catch (e) {
|
||||
if (isDebugMode) {
|
||||
throw e;
|
||||
} else {
|
||||
output.json({
|
||||
error: true,
|
||||
message: e
|
||||
});
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
17
package.json
一般檔案
17
package.json
一般檔案
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "sharepoint-webdav-oauth2-bot",
|
||||
"version": "1.0.0",
|
||||
"description": "sharepoint-webdav-oauth2-bot",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Simon Vieille <simon@deblan.fr>",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"class.extend": "^0.9.2",
|
||||
"crawler": "^1.1.2",
|
||||
"minimist": "^1.2.0",
|
||||
"trim": "0.0.1"
|
||||
}
|
||||
}
|
59
src/console/input.js
一般檔案
59
src/console/input.js
一般檔案
|
@ -0,0 +1,59 @@
|
|||
"use strict";
|
||||
|
||||
var Minimist = require('minimist');
|
||||
var Class = require('class.extend');
|
||||
|
||||
var Input = Class.extend('Input', {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object process
|
||||
*/
|
||||
init: function(process) {
|
||||
this.args = Minimist(process.argv.slice(2));
|
||||
this.node = process.argv[0];
|
||||
this.script = process.argv[1];
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the value of the given name argument.
|
||||
*
|
||||
* @param string name
|
||||
* @param mixed default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
get: function(name, defaultValue) {
|
||||
if (this.has(name)) {
|
||||
return this.args[name];
|
||||
}
|
||||
|
||||
if (defaultValue !== undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the given argument name exists.
|
||||
*
|
||||
* @param string name
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
has: function(name) {
|
||||
return this.args.hasOwnProperty(name);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return if args is empty.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
empty: function() {
|
||||
return Object.keys(this.args).length === 1;
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = Input;
|
37
src/console/output.js
一般檔案
37
src/console/output.js
一般檔案
|
@ -0,0 +1,37 @@
|
|||
"use strict";
|
||||
|
||||
var Class = require('class.extend');
|
||||
|
||||
var Output = Class.extend('Output', {
|
||||
/**
|
||||
* Convert and print data to json.
|
||||
*
|
||||
* @param mixed data
|
||||
*/
|
||||
json: function(data, pretty) {
|
||||
data = JSON.stringify(
|
||||
data,
|
||||
function(key, value) {
|
||||
if (value === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
pretty ? 2 : null
|
||||
);
|
||||
|
||||
return this.write(data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Print data.
|
||||
*
|
||||
* @param mixed data
|
||||
*/
|
||||
write: function(data) {
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Output;
|
53
src/cookie-bag.js
一般檔案
53
src/cookie-bag.js
一般檔案
|
@ -0,0 +1,53 @@
|
|||
var trim = require('trim');
|
||||
|
||||
var CookieBag = function() {
|
||||
this.bag = [];
|
||||
}
|
||||
|
||||
CookieBag.prototype.add = function(name, value) {
|
||||
this.bag[name] = name + '=' + value;
|
||||
}
|
||||
|
||||
CookieBag.prototype.get = function(name) {
|
||||
var str = this.bag[name] || null;
|
||||
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = str.indexOf('=');
|
||||
|
||||
return str.substr(index + 1);
|
||||
}
|
||||
|
||||
CookieBag.prototype.toString = function() {
|
||||
var data = [];
|
||||
|
||||
for (var i in this.bag) {
|
||||
data.push(this.bag[i]);
|
||||
}
|
||||
|
||||
return data.join('; ');
|
||||
}
|
||||
|
||||
CookieBag.prototype.handleResponse = function(response) {
|
||||
var headers = response.headers || {};
|
||||
var cookies = headers['set-cookie'] || [];
|
||||
var that = this;
|
||||
|
||||
cookies.forEach(function(cookie) {
|
||||
var def = cookie.split(';')[0];
|
||||
var index = def.indexOf('=');
|
||||
|
||||
var name = def.substr(0, index);
|
||||
var value = def.substr(index + 1);
|
||||
|
||||
that.add(name, value);
|
||||
});
|
||||
}
|
||||
|
||||
CookieBag.prototype.clean = function() {
|
||||
this.bag = [];
|
||||
}
|
||||
|
||||
module.exports = CookieBag;
|
26
src/logger.js
一般檔案
26
src/logger.js
一般檔案
|
@ -0,0 +1,26 @@
|
|||
var output = new(require('./console/output'));
|
||||
var input = new(require('./console/input'))(process);
|
||||
|
||||
var logCrawlerDebug = input.has('crawler-debug');
|
||||
var logCrawlerInfo = input.has('crawler-info');
|
||||
var logCrawlerError = input.has('crawler-error');
|
||||
|
||||
var writeLog = function(level, message) {
|
||||
return output.write('[' + level.toUpperCase() + '] ' + message);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
log: function(level, message) {
|
||||
if (level === 'debug' && logCrawlerDebug) {
|
||||
return writeLog(level, message);
|
||||
}
|
||||
|
||||
if (level === 'info' && logCrawlerInfo) {
|
||||
return writeLog(level, message);
|
||||
}
|
||||
|
||||
if (level === 'error' && logCrawlerError) {
|
||||
return writeLog(level, message);
|
||||
}
|
||||
},
|
||||
};
|
5
src/preg-match.js
一般檔案
5
src/preg-match.js
一般檔案
|
@ -0,0 +1,5 @@
|
|||
var pregMatch = function(regex, content) {
|
||||
return content.match(regex);
|
||||
}
|
||||
|
||||
module.exports = pregMatch;
|
新增問題並參考