httpServ.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. var http = require("http")
  2. ,https = require("https")
  3. ,clientSession = require("client-sessions")
  4. ,Url = require("./url.js").Url
  5. ,config = require("../config.js")
  6. ,sessionManager = require("./session.js").SessionManager
  7. ,Slack = require("./slack.js").Slack
  8. ,slackManager = require("./slackManager.js").SlackManager
  9. ,FaviconWriter = require("./faviconWriter.js").FaviconWriter;
  10. function Server(port) {
  11. var ctx = this;
  12. this.httpServ = http.createServer(function(req, res) {
  13. res.ended = false;
  14. res.on('end', () => {
  15. res.ended = true;
  16. });
  17. ctx.onRequest(req, res);
  18. });
  19. this.httpServ.listen(port, ctx.onListen);
  20. }
  21. Server.parseCookies = function(req) {
  22. var cookies = req.headers.cookie
  23. ,cookieObj = null;
  24. if (cookies) {
  25. cookieObj = {};
  26. cookies = cookies.split(";");
  27. for (var cookieIndex =0, nbCookies =cookies.length; cookieIndex < nbCookies; cookieIndex++) {
  28. var cookieParts = cookies[cookieIndex].indexOf("=")
  29. ,cookieKey = null
  30. ,cookieValue = null;
  31. if (cookieParts === -1) {
  32. cookieKey = cookies[cookieIndex].trim();
  33. } else {
  34. cookieKey = cookies[cookieIndex].substr(0, cookieParts).trim();
  35. cookieValue = cookies[cookieIndex].substr(cookieParts +1).trim();
  36. }
  37. cookieObj[cookieKey] = cookieValue;
  38. }
  39. }
  40. return cookieObj;
  41. };
  42. Server.stringifyCookies = function(cookies) {
  43. var cookieString = "";
  44. for (var cookieKey in cookies) {
  45. cookieString += cookieString;
  46. if (cookies[cookieString] !== null) {
  47. cookieString += "=";
  48. }
  49. cookieString += "; ";
  50. }
  51. return cookieString;
  52. };
  53. Server.prototype.onListen = function() {
  54. console.log("onListen");
  55. };
  56. function redirectToSlackAuth(res) {
  57. res.writeHeader("302", {
  58. Location: "https://slack.com/oauth/authorize"
  59. +"?client_id=" +config.login.slack.clientId
  60. +"&scope=" +slackManager.getScope().join(",")
  61. +"&redirect_uri=" +config.rootUrl
  62. });
  63. res.end();
  64. }
  65. Server.prototype.onRequest = function(req, res) {
  66. req.reqT = Date.now();
  67. req.cookies = Server.parseCookies(req);
  68. req.session = sessionManager.forRequest(req);
  69. req.urlObj = new Url(req.url);
  70. if (req.urlObj.isTemplate() && req.urlObj.template.needLogin === false) {
  71. var resp = req.urlObj.template.exec(req, res);
  72. res.writeHeader(resp.status || 200);
  73. res.end(resp.body);
  74. return;
  75. } else if (!req.session || !req.session.slackToken) {
  76. if (req.urlObj.queryTokens.code) {
  77. Slack.getOauthToken(req.urlObj.queryTokens.code, config.rootUrl, (token) => {
  78. if (token) {
  79. req.session = sessionManager.lazyForRequest(req);
  80. req.session.setSlackToken(req.reqT, token);
  81. res.writeHeader("302", {
  82. Location: config.rootUrl
  83. ,"Set-Cookie": "sessID="+req.session.sessId
  84. });
  85. sessionManager.saveSession(req.session);
  86. res.end();
  87. } else {
  88. redirectToSlackAuth(res);
  89. }
  90. });
  91. } else {
  92. res.writeHeader("302", {
  93. Location: "login"
  94. });
  95. res.end();
  96. }
  97. } else if (req.urlObj.isTemplate()) {
  98. var resp = req.urlObj.template.exec(req, res);
  99. res.writeHeader(resp.status || 200);
  100. res.end(resp.body);
  101. return;
  102. } else if (req.urlObj.isPublic()) {
  103. if (!config.isDebug)
  104. res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
  105. res.setHeader('Content-Length', req.urlObj.serve.stat.size);
  106. res.writeHeader("200");
  107. req.urlObj.getReadStream().pipe(res, { end: true });
  108. sessionManager.saveSession(req.session);
  109. return; // async pipe will close when finished
  110. } else if (req.urlObj.match(["favicon.png"])) {
  111. if (!config.isDebug)
  112. res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
  113. var unreadHi = (req.urlObj.queryTokens.h && req.urlObj.queryTokens.h[0]) ? parseInt(req.urlObj.queryTokens.h[0], 10) : 0
  114. ,unread = (req.urlObj.queryTokens.m && req.urlObj.queryTokens.m[0]) ? parseInt(req.urlObj.queryTokens.m[0], 10) : 0;
  115. FaviconWriter.write(unreadHi, unread, (buf) => {
  116. res.writeHeader("200");
  117. res.end(buf);
  118. });
  119. sessionManager.saveSession(req.session);
  120. return;
  121. } else {
  122. // Api / dynamic content
  123. var apiSuccess = false;
  124. res.slack = slackManager.lazyGet(req.session, req.reqT);
  125. if (req.urlObj.match(["api", "hist"])) {
  126. if (!req.urlObj.queryTokens.room) {
  127. res.writeHeader("400", "Bad request");
  128. } else {
  129. var allFound = true;
  130. req.urlObj.queryTokens.room.forEach(function(targetId) {
  131. if (!res.slack.data.channels[targetId]) {
  132. allFound = false;
  133. }
  134. res.slack.fetchHistory(targetId);
  135. });
  136. if (allFound)
  137. res.writeHeader("204", "No Content");
  138. else
  139. res.writeHeader("404", "Channel not found");
  140. }
  141. sessionManager.saveSession(req.session);
  142. res.end();
  143. } else if (req.urlObj.match(["api", "typing"])) {
  144. if (!req.urlObj.queryTokens.room) {
  145. res.writeHeader("400", "Bad request");
  146. res.end();
  147. } else {
  148. var chan = res.slack.data.channels[req.urlObj.queryTokens.room[0]];
  149. if (!chan) {
  150. res.writeHeader("404", "Chan not found");
  151. } else {
  152. res.slack.sendTyping(chan);
  153. res.writeHeader("204", "No Content");
  154. }
  155. res.end();
  156. }
  157. } else if (req.urlObj.match(["api", "cmd"])) {
  158. if (!req.urlObj.queryTokens.room ||
  159. !req.urlObj.queryTokens.cmd) {
  160. res.writeHeader("400", "Bad request");
  161. res.end();
  162. } else {
  163. var chan = res.slack.data.channels[req.urlObj.queryTokens.room[0]]
  164. ,cmd = res.slack.data.commands.data['/' +req.urlObj.queryTokens.cmd[0]];
  165. if (!chan) {
  166. res.writeHeader("404", "Chan not found");
  167. } else if (!cmd) {
  168. res.writeHeader("404", "No such command");
  169. } else {
  170. var args = req.urlObj.queryTokens.args ? req.urlObj.queryTokens.args[0] : "";
  171. if (args === true)
  172. args = "";
  173. res.slack.sendCommand(chan, cmd, args);
  174. res.writeHeader("204", "No Content");
  175. }
  176. res.end();
  177. }
  178. } else if (req.urlObj.match(["api", "markread"])) {
  179. if (!req.urlObj.queryTokens.room || !req.urlObj.queryTokens.ts) {
  180. res.writeHeader("400", "Bad request");
  181. res.end();
  182. } else {
  183. var chan = res.slack.data.channels[req.urlObj.queryTokens.room[0]]
  184. ,ts = parseFloat(req.urlObj.queryTokens.ts[0]);
  185. if (!chan)
  186. res.writeHeader("404", "Chan Not Found");
  187. else if (isNaN(ts))
  188. res.writeHeader("400", "Invalid date");
  189. else
  190. res.slack.markRead(chan, ts);
  191. res.end();
  192. }
  193. sessionManager.saveSession(req.session);
  194. } else if (req.urlObj.match(["api", "avatar"])) {
  195. if (!req.urlObj.queryTokens.user) {
  196. res.writeHeader("400", "Bad request");
  197. res.end();
  198. } else {
  199. var user = res.slack.data.users[req.urlObj.queryTokens.user[0]];
  200. if (!user) {
  201. res.writeHeader("404", "User Not Found");
  202. res.end();
  203. } else {
  204. var url = user.icons.small;
  205. if (url.substr(0, 7) === "http://")
  206. http.get(url, (d) => {
  207. d.pipe(res, { end: true });
  208. });
  209. else if (url.substr(0, 8) === "https://")
  210. https.get(url, (d) => {
  211. d.pipe(res, { end: true });
  212. });
  213. }
  214. }
  215. sessionManager.saveSession(req.session);
  216. } else if (req.urlObj.match(["api", "msg"])) {
  217. if (req.method === 'POST') {
  218. if (!req.urlObj.queryTokens.room || !req.urlObj.queryTokens.text) {
  219. res.writeHeader("400", "Bad request");
  220. } else {
  221. var chan = res.slack.data.channels[req.urlObj.queryTokens.room[0]];
  222. if (chan) {
  223. var attachments = null;
  224. if (req.urlObj.queryTokens.attachments) {
  225. try { attachments = JSON.parse(decodeURIComponent(req.urlObj.queryTokens.attachments[0])); }
  226. catch (e) {}
  227. }
  228. if (req.urlObj.queryTokens.me)
  229. res.slack.sendMeMsg(chan, req.urlObj.queryTokens.text);
  230. else
  231. res.slack.sendMsg(chan, req.urlObj.queryTokens.text, attachments);
  232. res.writeHeader("204", "No Content");
  233. } else {
  234. res.writeHeader("404", "Channel not found");
  235. }
  236. }
  237. } else if (req.method === "DELETE") {
  238. if (!req.urlObj.queryTokens.room || !req.urlObj.queryTokens.ts) {
  239. res.writeHeader("400", "Bad request");
  240. } else {
  241. var chan = res.slack.data.channels[req.urlObj.queryTokens.room[0]];
  242. if (chan) {
  243. res.slack.removeMsg(chan, req.urlObj.queryTokens.ts[0]);
  244. res.writeHeader("204", "No Content");
  245. } else {
  246. res.writeHeader("404", "Channel not found");
  247. }
  248. }
  249. } else if (req.method === "PUT") {
  250. if (!req.urlObj.queryTokens.room || !req.urlObj.queryTokens.ts || !req.urlObj.queryTokens.text) {
  251. res.writeHeader("400", "Bad request");
  252. } else {
  253. var chan = res.slack.data.channels[req.urlObj.queryTokens.room[0]];
  254. if (chan) {
  255. res.slack.editMsg(chan, req.urlObj.queryTokens.ts[0], req.urlObj.queryTokens.text);
  256. res.writeHeader("204", "No Content");
  257. } else {
  258. res.writeHeader("404", "Channel not found");
  259. }
  260. }
  261. } else {
  262. res.writeHeader("400", "Bad request");
  263. }
  264. sessionManager.saveSession(req.session);
  265. res.end();
  266. } else if (req.urlObj.match(["api", "reaction"])) {
  267. var chanId = req.urlObj.queryTokens["room"] ? req.urlObj.queryTokens["room"][0] : undefined
  268. ,msgId = req.urlObj.queryTokens["msg"] ? req.urlObj.queryTokens["msg"][0] : undefined
  269. ,reaction = req.urlObj.queryTokens["reaction"] ? req.urlObj.queryTokens["reaction"][0] : undefined;
  270. if (chanId && msgId && reaction) {
  271. var chan = res.slack.data.channels[chanId];
  272. if (!chan) {
  273. res.writeHeader("404", "Channel Not Found");
  274. } else if (req.method === 'POST') {
  275. res.writeHeader("204", "No Content");
  276. res.slack.addReaction(chan, msgId, reaction);
  277. } else if (req.method === 'DELETE') {
  278. res.writeHeader("204", "No Content");
  279. res.slack.removeReaction(chan, msgId, reaction);
  280. } else {
  281. res.writeHeader("405", "Method not allowed");
  282. }
  283. } else {
  284. res.writeHeader("400", "Missing Parameter");
  285. }
  286. sessionManager.saveSession(req.session);
  287. res.end();
  288. } else if (req.urlObj.match(["api", "file"])) {
  289. sessionManager.saveSession(req.session);
  290. if (req.urlObj.queryTokens["room"]) {
  291. var chan = res.slack.data.channels[req.urlObj.queryTokens["room"][0]];
  292. if (chan) {
  293. var uploadRequest = res.slack.openUploadFileStream(chan, req.headers["content-type"], (errorMsg) => {
  294. if (!errorMsg)
  295. res.writeHeader("204", "No Content");
  296. else
  297. res.writeHeader("500", errorMsg);
  298. res.end();
  299. });
  300. req.on('end', () => {
  301. uploadRequest.end();
  302. });
  303. req.pipe(uploadRequest);
  304. } else {
  305. res.writeHeader("404", "Channel Not Found");
  306. res.end();
  307. }
  308. } else {
  309. res.writeHeader("400", "Bad Request");
  310. res.end();
  311. }
  312. } else if (req.urlObj.match(["api", "attachmentAction"])) {
  313. sessionManager.saveSession(req.session);
  314. res.slack.sendAction(req.headers["content-type"], req, (result) => {
  315. res.end(result);
  316. });
  317. } else if (req.urlObj.match(["api"])) {
  318. res.slack.onRequest(
  319. (req.urlObj.queryTokens.v ? req.urlObj.queryTokens.v[0] : 0) || 0
  320. , (slack, newData) => {
  321. if (!res.ended) {
  322. try {
  323. if (!slack.connected) {
  324. res.writeHeader("403", {
  325. "Content-Type": "application/json"
  326. });
  327. res.end(slack.error);
  328. } else {
  329. res.writeHeader("200", {
  330. "Content-Type": "application/json"
  331. });
  332. res.end(JSON.stringify(newData));
  333. }
  334. } catch (e) {}
  335. }
  336. sessionManager.saveSession(req.session);
  337. });
  338. } else {
  339. console.log(JSON.stringify(req.session));
  340. console.log(JSON.stringify(req.urlObj));
  341. console.log(JSON.stringify(req.cookies));
  342. res.writeHeader("404", "Not Found");
  343. res.end();
  344. }
  345. }
  346. };
  347. module.exports.HttpServ = Server;