Arca base64 autodecoder

Arca.live Base64 auto decoder

当前为 2023-12-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Arca base64 autodecoder
  3. // @name:ko 아카라이브 Base64 자동 디코더
  4. // @version 1.16
  5. // @author Laria
  6. // @match https://arca.live/b/*/*
  7. // @description Arca.live Base64 auto decoder
  8. // @description:ko 아카라이브 Base64 자동 복호화 스크립트
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=arca.live
  10. // @license MIT
  11. // @encoding utf-8
  12. // @run-at document-end
  13. // @supportURL https://greasyfork.org/ko/scripts/482577-arca-base64-autodecoder
  14. // @namespace https://greasyfork.org/users/1235854
  15. // ==/UserScript==
  16.  
  17. /*
  18. * == Change log ==
  19. * 1.0 - Release
  20. * 1.1 - Invalid character update (replace -> replaceAll)
  21. * 1.11 - Improved show multiple links
  22. * 1.12 - Show Single links Bugfix
  23. * 1.13 - Bugfix 1.12
  24. * 1.14 - Base64 add padding func
  25. * 1.15 - Add annotation, display improvements
  26. * 1.16 - Display improved - CSS applied
  27. */
  28.  
  29. //base64 encoded(http:/*, https:/*) string prefix, defalut depth : 3 / Caution! browser performance impact..
  30. const regArr = [
  31. /(aHR0cDovL|aHR0cHM6Ly)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 1 time
  32. /(YUhSMGNEb3ZM|YUhSMGNITTZMe)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 2 time
  33. /(WVVoU01HTkViM1pN|WVVoU01HTklUVFpNZ)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 3 time
  34. // /(V1ZWb1UwMUhUa1ZpTTFwT|V1ZWb1UwMUhUa2xVVkZwTl)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 4 time
  35. // /(VjFaV2IxVXdNVWhVYTFacFRURndU|VjFaV2IxVXdNVWhVYTJ4VlZrWndUb)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 5 time
  36. // /(VmpGYVYySXhWWGROVldoVllURmFjRlJVUm5kV|VmpGYVYySXhWWGROVldoVllUSjRWbFpyV25kVW)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 6 time
  37. // /(Vm1wR1lWWXlTWGhXV0dST1ZsZG9WbGxVUm1GalJsSlZVbTVrV|Vm1wR1lWWXlTWGhXV0dST1ZsZG9WbGxVU2pSV2JGcHlWMjVrVl)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 7 time
  38. ];
  39. //max attempt decode depth, regArr length
  40. const max_iter = regArr.length;
  41. //regex prefix - drag
  42. const regInvalid = /[^\w\+\/=]/;
  43.  
  44. //auto add padding - add '=' padding in base64 encoded string
  45. function base64AddPadding(str) {
  46. return str + Array((4 - str.length % 4) % 4 + 1).join('=');
  47. }
  48.  
  49. //base64 decode
  50. var Base64 = {
  51. _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  52. decode : function (input) {
  53. var output = "";
  54. var chr1, chr2, chr3;
  55. var enc1, enc2, enc3, enc4;
  56. var i = 0;
  57.  
  58. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  59.  
  60. while (i < input.length) {
  61. enc1 = this._keyStr.indexOf(input.charAt(i++));
  62. enc2 = this._keyStr.indexOf(input.charAt(i++));
  63. enc3 = this._keyStr.indexOf(input.charAt(i++));
  64. enc4 = this._keyStr.indexOf(input.charAt(i++));
  65.  
  66. chr1 = (enc1 << 2) | (enc2 >> 4);
  67. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  68. chr3 = ((enc3 & 3) << 6) | enc4;
  69.  
  70. output = output + String.fromCharCode(chr1);
  71.  
  72. if (enc3 != 64) {
  73. output = output + String.fromCharCode(chr2);
  74. }
  75. if (enc4 != 64) {
  76. output = output + String.fromCharCode(chr3);
  77. }
  78. }
  79.  
  80. output = Base64._utf8_decode(output);
  81. return output;
  82. },
  83. // private method for UTF-8 decoding
  84. _utf8_decode : function (utftext) {
  85. var string = "";
  86. var i = 0;
  87. var c = 0;
  88. var c1 = 0;
  89. var c2 = 0;
  90. var c3 = 0;
  91.  
  92. while ( i < utftext.length ) {
  93. c = utftext.charCodeAt(i);
  94. if (c < 128) {
  95. string += String.fromCharCode(c);
  96. i++;
  97. }
  98. else if((c > 191) && (c < 224)) {
  99. c2 = utftext.charCodeAt(i+1);
  100. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  101. i += 2;
  102. }
  103. else {
  104. c2 = utftext.charCodeAt(i+1);
  105. c3 = utftext.charCodeAt(i+2);
  106. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  107. i += 3;
  108. }
  109. }
  110. return string;
  111. }
  112. };
  113.  
  114. var hindex = 0; //total decode count
  115.  
  116. //drag function comparison
  117. var lastSelected = document;
  118. var lastSelectedTime = Date.now();
  119.  
  120. //create link each components
  121. function createLink(src, index, url, depth) {
  122. //n번째 링크 (base64 깊이: 0) [ ABCDEF= ]
  123. return '<a href="' + url + '" title="' + url + ' (새 창으로 열기)" target="_blank" rel="external nofollow noopener noreferrer">' + index.toString() + '번째 링크 (base64 깊이: ' + depth.toString() + ')</a> [ <span style="font-size: 87.5%;color: rgb(71 188 115);">' + src.toString() + '</span> ]';
  124. }
  125.  
  126. //decode & generate
  127. function replacerGen(numIter) {
  128. return function(source) {
  129. try {
  130. rstring = ""; //return msg
  131. console.log(source); //source
  132.  
  133. //decode
  134. var converted = Base64.decode(base64AddPadding(source));
  135. //attempt to decode nested base64 encoded string
  136. for(var i=0; i<numIter; i++) {
  137. converted = Base64.decode(base64AddPadding(converted));
  138. }
  139. hindex++;
  140.  
  141. //remove invalid string - �
  142. converted = decodeURI(encodeURI(converted).replaceAll('%00', ''));
  143.  
  144. //split by new line
  145. converted = converted.split(/\r?\n/);
  146. //single component
  147. if (converted.length == 2 && converted[converted.length-1] == '') {
  148. rstring += createLink(source, hindex, converted[0], numIter+1);
  149. //multiple component
  150. } else if (converted.length > 1) {
  151. rstring += '[ <span style="font-size: 87.5%;color: rgb(71 188 115);">' + source.toString() + '</span> ]';
  152. nindex = 1;
  153. converted.forEach(function(j) {
  154. if (j != '') {
  155. rstring += '<br>' + createLink('링크 자동 분할 : ' + nindex.toString() + '번째', hindex, j, numIter+1);
  156. hindex++;
  157. nindex++;
  158. }
  159. });
  160. //last components
  161. hindex--;
  162. nindex--;
  163.  
  164. rstring = '<span style="color: rgb(232 62 140);"><b><i>분할된 링크 총 ' + nindex + '개</i></b></span> ' + rstring;
  165. } else rstring += createLink(source, hindex, converted, numIter+1);
  166. return rstring;
  167. } catch(e) {
  168. console.log(e);
  169. console.log('base64 변환 실패 : ' + source);
  170. }
  171. return '[ base64 변환 실패 : ' + source + ' ]';
  172. };
  173. }
  174.  
  175. //user drag event
  176. //function disabled
  177. function selClicked(event) {
  178. var sel = document.getSelection().toString();
  179. if (!sel.match(regInvalid) && sel.length >= 10 && lastSelectedTime + 200 < Date.now()) {
  180. try {
  181. var converted = decodeURI(encodeURI(Base64.decode(base64AddPadding(sel))).replaceAll('%00', ''));
  182. this.innerHTML = this.innerHTML.replace(sel, converted);
  183. this.removeEventListener('click', selClicked);
  184. } catch (e) {
  185. return;
  186. } finally {
  187. }
  188. }
  189. }
  190.  
  191. //main
  192. (function() {
  193. 'use strict';
  194.  
  195. //article
  196. var article = document.getElementsByClassName("article-content")[0];
  197. for(var i=0; i<max_iter; i++) {
  198. article.innerHTML = article.innerHTML.replaceAll(regArr[i], replacerGen(i));
  199. }
  200.  
  201. //comment
  202. var comments = document.getElementsByClassName("list-area");
  203. if(comments.length != 0) {
  204. for(var j=0; j<max_iter; j++) {
  205. comments[0].innerHTML = comments[0].innerHTML.replaceAll(regArr[j], replacerGen(j));
  206. }
  207. }
  208.  
  209. /*
  210. //user drag
  211. document.addEventListener('selectionchange', function() {
  212. var sel = document.getSelection().anchorNode;
  213. if(sel) {
  214. sel = sel.parentElement;
  215. if(sel != lastSelected) {
  216. lastSelected.removeEventListener('click', selClicked);
  217. sel.addEventListener('click', selClicked);
  218. lastSelected = sel;
  219. lastSelectedTime = Date.now();
  220. }
  221. }
  222. })
  223. */
  224.  
  225. })();