1
0
フォーク 0
このコミットが含まれているのは:
Simon Vieille 2018-09-11 10:36:58 +02:00
コミット a75e5e12a9
この署名に対応する既知のキーがデータベースに存在しません
GPGキーID: 919533E2B946EA10
8個のファイルの変更489行の追加0行の削除

2
.gitignore vendored ノーマルファイル
ファイルの表示

@ -0,0 +1,2 @@
login
node_modules/

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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -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 ノーマルファイル
ファイルの表示

@ -0,0 +1,5 @@
var pregMatch = function(regex, content) {
return content.match(regex);
}
module.exports = pregMatch;