Advertisement
Guest User

Untitled

a guest
Jun 19th, 2019
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.18 KB | None | 0 0
  1. addEventListener('fetch', event => {
  2. event.respondWith(handleRequest(event.request))
  3. })
  4.  
  5. /**
  6. * Fetch and log a request
  7. * @param {Request} request
  8. */
  9. async function handleRequest(request) {
  10. const response = await fetch(request);
  11.  
  12. var ctype = response.headers.get('content-type');
  13. if (ctype.startsWith('text/html') === false)
  14. return response; //Only parse html body
  15.  
  16. let { readable, writable } = new TransformStream();
  17. let promise = injectScript(response.body, writable, "<script>var test = 1;</script>");
  18. return new Response(readable, response);
  19. }
  20.  
  21. async function injectScript(readable, writable, injectable) {
  22. let decoder = new TextDecoder('utf-8');
  23. let encoder = new TextEncoder('utf-8'); //By the way: once we start encoding we can't simply forward byte arrays anymore
  24. let reader = readable.getReader();
  25. let writer = writable.getWriter();
  26.  
  27. let done = await parseForInjection(reader, writer, decoder, encoder, injectable);
  28. if (done) return; //Very edge case: Somehow </head> is never found?
  29. await forwardTheRest(reader, writer, decoder, encoder);
  30. }
  31.  
  32. async function parseForInjection(reader, writer, decoder, encoder, injectable)
  33. {
  34. let textBuffer = '';
  35. for (;;) {
  36. let {value, done } = await reader.read();
  37. if (done) {
  38. if (textBuffer.length > 0) {
  39. //Very edge case: Somehow </head> is never found?
  40. let doneBytes = encoder.encode(textBuffer);
  41. await writer.write(doneBytes);
  42. textBuffer = '';
  43. }
  44. await writer.close();
  45. return true;
  46. }
  47.  
  48. textBuffer += decoder.decode(value); //Once we start, we must always use encoder/decoder
  49. var foundInd = textBuffer.indexOf("</head>"); //Don't use regex, this is all we need and it's faster
  50. if (foundInd === -1)
  51. {
  52. let isLikelyHeadTagSplit = CheckIfHeadTagIsSplit(textBuffer);
  53. if (isLikelyHeadTagSplit)
  54. {
  55. continue; //Keep buiding up the textBuffer
  56. }
  57. else
  58. {
  59. //Not found:
  60. let theseBytes = encoder.encode(textBuffer);
  61. await writer.write(theseBytes);
  62. textBuffer = '';
  63. continue;
  64. }
  65. }
  66.  
  67. //Found:
  68. await doInjection(textBuffer, foundInd, injectable, encoder, writer);
  69. //We don't need to clear textBuffer, it's about to go out of scope
  70.  
  71. return false; //
  72. }
  73. }
  74.  
  75. async function forwardTheRest(reader, writer, decoder, encoder)
  76. {
  77. for (;;) {
  78. let { value, done } = await reader.read()
  79. if (done) {
  80. await writer.close();
  81. return;
  82. }
  83.  
  84. //Once we start, we must always use encoder/decoder
  85. let thisText = decoder.decode(value);
  86. let theseBytes = encoder.encode(thisText);
  87. await writer.write(theseBytes)
  88. }
  89. }
  90.  
  91. function CheckIfHeadTagIsSplit(textBuffer) {
  92. //It's highly unlikely, so do a very basic probabilistic check first
  93. let lastChar = textBuffer[textBuffer.length - 1];
  94. let splitIsPossible = (lastChar === "<" ||
  95. lastChar === "/" ||
  96. lastChar === "h" ||
  97. lastChar === "e" ||
  98. lastChar === "a" ||
  99. lastChar === "d");
  100.  
  101. if (splitIsPossible == false)
  102. {
  103. return false;
  104. }
  105.  
  106. //It's likely, so now do a more exact test
  107. if (textBuffer.endsWith("<"))
  108. return true; //Maybe
  109. if (textBuffer.endsWith("</"))
  110. return true; //Maybe (could be </Script>)
  111. if (textBuffer.endsWith("</h"))
  112. return true; //Very Likely (I can't think of any tags for the head section other than "/head")
  113. if (textBuffer.endsWith("</he"))
  114. return true; //Super Likely
  115. if (textBuffer.endsWith("</hea"))
  116. return true; //Super Likely
  117. if (textBuffer.endsWith("</head"))
  118. return true; //Super likely
  119.  
  120. return false;
  121. }
  122.  
  123. async function doInjection(textBuffer, foundInd, injectable, encoder, writer)
  124. {
  125. let textBefore = textBuffer.substr(0, foundInd);
  126. let bytes = encoder.encode(textBefore);
  127. await writer.write(bytes);
  128.  
  129. bytes = encoder.encode(injectable);
  130. await writer.write(bytes);
  131.  
  132. let textAfter = textBuffer.substr(foundInd, textBuffer.length - foundInd);
  133. bytes = encoder.encode(textAfter);
  134. await writer.write(bytes);
  135. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement