httpServ.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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.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.session || !req.session.slackToken) {
  71. if (req.urlObj.queryTokens.code) {
  72. Slack.getOauthToken(req.urlObj.queryTokens.code, config.rootUrl, (token) => {
  73. if (token) {
  74. req.session = sessionManager.lazyForRequest(req);
  75. req.session.setSlackToken(req.reqT, token);
  76. res.writeHeader("302", {
  77. Location: config.rootUrl
  78. ,"Set-Cookie": "sessID="+req.session.sessId
  79. });
  80. sessionManager.saveSession(req.session);
  81. res.end();
  82. } else {
  83. redirectToSlackAuth(res);
  84. }
  85. });
  86. } else {
  87. redirectToSlackAuth(res);
  88. }
  89. } else if (req.urlObj.isPublic()) {
  90. if (!config.isDebug)
  91. res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
  92. res.setHeader('Content-Length', req.urlObj.serve.stat.size);
  93. res.writeHeader("200");
  94. req.urlObj.getReadStream().pipe(res, { end: true });
  95. sessionManager.saveSession(req.session);
  96. return; // async pipe will close when finished
  97. } else if (req.urlObj.match(["favicon.png"])) {
  98. if (!config.isDebug)
  99. res.setHeader('Cache-Control', 'private, max-age=' +15 * 60);
  100. var unreadHi = (req.urlObj.queryTokens.h && req.urlObj.queryTokens.h[0]) ? parseInt(req.urlObj.queryTokens.h[0], 10) : 0
  101. ,unread = (req.urlObj.queryTokens.m && req.urlObj.queryTokens.m[0]) ? parseInt(req.urlObj.queryTokens.m[0], 10) : 0;
  102. FaviconWriter.write(unreadHi, unread, (buf) => {
  103. res.writeHeader("200");
  104. res.end(buf);
  105. });
  106. sessionManager.saveSession(req.session);
  107. return;
  108. } else {
  109. // Api / dynamic content
  110. var apiSuccess = false;
  111. res.slack = slackManager.lazyGet(req.session);
  112. if (req.urlObj.match(["api", "hist"])) {
  113. if (!req.urlObj.queryTokens.room) {
  114. res.writeHeader("400", "Bad request");
  115. } else {
  116. var allFound = true;
  117. req.urlObj.queryTokens.room.forEach(function(targetId) {
  118. if (!res.slack.data.getChannel(targetId)) {
  119. allFound = false;
  120. }
  121. res.slack.fetchHistory(targetId);
  122. });
  123. if (allFound)
  124. res.writeHeader("204", "No Content");
  125. else
  126. res.writeHeader("404", "Channel not found");
  127. }
  128. sessionManager.saveSession(req.session);
  129. res.end();
  130. } else if (req.urlObj.match(["api", "avatar"])) {
  131. if (!req.urlObj.queryTokens.user) {
  132. res.writeHeader("400", "Bad request");
  133. res.end();
  134. } else {
  135. var user = res.slack.data.getMember(req.urlObj.queryTokens.user[0]);
  136. if (!user) {
  137. res.writeHeader("404", "User Not Found");
  138. res.end();
  139. } else {
  140. var url = user.icons.image_48;
  141. if (url.substr(0, 7) === "http://")
  142. http.get(url, (d) => {
  143. d.pipe(res, { end: true });
  144. });
  145. else if (url.substr(0, 8) === "https://")
  146. https.get(url, (d) => {
  147. d.pipe(res, { end: true });
  148. });
  149. }
  150. }
  151. sessionManager.saveSession(req.session);
  152. } else if (req.urlObj.match(["api", "msg"])) {
  153. if (req.method === 'POST') {
  154. if (!req.urlObj.queryTokens.room || !req.urlObj.queryTokens.text) {
  155. res.writeHeader("400", "Bad request");
  156. } else {
  157. var chan = res.slack.data.getChannel(req.urlObj.queryTokens.room[0]);
  158. if (chan) {
  159. var attachments = null;
  160. if (req.urlObj.queryTokens.attachments) {
  161. try { attachments = JSON.parse(decodeURIComponent(req.urlObj.queryTokens.attachments[0])); }
  162. catch (e) {}
  163. }
  164. if (req.urlObj.queryTokens.me)
  165. res.slack.sendMeMsg(chan, req.urlObj.queryTokens.text);
  166. else
  167. res.slack.sendMsg(chan, req.urlObj.queryTokens.text, attachments);
  168. res.writeHeader("204", "No Content");
  169. } else {
  170. res.writeHeader("404", "Channel not found");
  171. }
  172. }
  173. } else if (req.method === "DELETE") {
  174. if (!req.urlObj.queryTokens.room || !req.urlObj.queryTokens.ts) {
  175. res.writeHeader("400", "Bad request");
  176. } else {
  177. var chan = res.slack.data.getChannel(req.urlObj.queryTokens.room[0]);
  178. if (chan) {
  179. res.slack.removeMsg(chan, req.urlObj.queryTokens.ts[0]);
  180. res.writeHeader("204", "No Content");
  181. } else {
  182. res.writeHeader("404", "Channel not found");
  183. }
  184. }
  185. } else {
  186. res.writeHeader("400", "Bad request");
  187. }
  188. sessionManager.saveSession(req.session);
  189. res.end();
  190. } else if (req.urlObj.match(["api", "reaction"])) {
  191. var chanId = req.urlObj.queryTokens["room"] ? req.urlObj.queryTokens["room"][0] : undefined
  192. ,msgId = req.urlObj.queryTokens["msg"] ? req.urlObj.queryTokens["msg"][0] : undefined
  193. ,reaction = req.urlObj.queryTokens["reaction"] ? req.urlObj.queryTokens["reaction"][0] : undefined;
  194. if (chanId && msgId && reaction) {
  195. var chan = res.slack.data.getChannel(chanId);
  196. if (!chan) {
  197. res.writeHeader("404", "Channel Not Found");
  198. } else if (req.method === 'POST') {
  199. res.writeHeader("204", "No Content");
  200. res.slack.addReaction(chan, msgId, reaction);
  201. } else if (req.method === 'DELETE') {
  202. res.writeHeader("204", "No Content");
  203. res.slack.removeReaction(chan, msgId, reaction);
  204. } else {
  205. res.writeHeader("405", "Method not allowed");
  206. }
  207. } else {
  208. res.writeHeader("400", "Missing Parameter");
  209. }
  210. sessionManager.saveSession(req.session);
  211. res.end();
  212. } else if (req.urlObj.match(["api", "file"])) {
  213. sessionManager.saveSession(req.session);
  214. if (req.urlObj.queryTokens["room"]) {
  215. var chan = res.slack.data.getChannel(req.urlObj.queryTokens["room"][0]);
  216. if (chan) {
  217. var uploadRequest = res.slack.openUploadFileStream(chan, req.headers["content-type"], (errorMsg) => {
  218. if (!errorMsg)
  219. res.writeHeader("204", "No Content");
  220. else
  221. res.writeHeader("500", errorMsg);
  222. res.end();
  223. });
  224. req.on('end', () => {
  225. uploadRequest.end();
  226. });
  227. req.pipe(uploadRequest);
  228. } else {
  229. res.writeHeader("404", "Channel Not Found");
  230. res.end();
  231. }
  232. } else {
  233. res.writeHeader("400", "Bad Request");
  234. res.end();
  235. }
  236. } else if (req.urlObj.match(["api"])) {
  237. res.slack.onRequest((req.urlObj.queryTokens.v ? req.urlObj.queryTokens.v[0] : 0) || 0, (slack, newData) => {
  238. if (!res.ended) {
  239. try {
  240. if (!slack.connected) {
  241. res.writeHeader("403", {
  242. "Content-Type": "application/json"
  243. });
  244. res.end(slack.error);
  245. } else {
  246. res.writeHeader("200", {
  247. "Content-Type": "application/json"
  248. });
  249. res.end(JSON.stringify(newData));
  250. }
  251. } catch (e) {}
  252. }
  253. sessionManager.saveSession(req.session);
  254. });
  255. } else {
  256. console.log(JSON.stringify(req.session));
  257. console.log(JSON.stringify(req.urlObj));
  258. console.log(JSON.stringify(req.cookies));
  259. res.writeHeader("404", "Not Found");
  260. res.end();
  261. }
  262. }
  263. };
  264. module.exports.HttpServ = Server;