Arca base64 autodecoder

아카라이브 Base64 자동 복호화

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

  1. // ==UserScript==
  2. // @name Arca base64 autodecoder
  3. // @version 1.13
  4. // @author Laria
  5. // @match https://arca.live/b/*/*
  6. // @description 아카라이브 Base64 자동 복호화
  7. // @icon https://www.google.com/s2/favicons?sz=64&domain=arca.live
  8. // @run-at document-end
  9. // @namespace https://greasyfork.org/users/1235854
  10. // ==/UserScript==
  11.  
  12. /*
  13. * 1.0 - Release
  14. * 1.1 - Invalid character update (replace -> replaceAll)
  15. * 1.11 - Improved show multiple links
  16. * 1.12 - Show Single links Bugfixlinks
  17. * 1.13 - Show Single links Bugfix
  18. */
  19.  
  20. const regArr = [
  21. /(aHR0cDovL|aHR0cHM6Ly)(\w|=|\+|\/)*(?=[^\+=\w\/])/g,
  22. /(YUhSMGNEb3ZM|YUhSMGNITTZMe)(\w|=|\+|\/)*(?=[^\+=\w\/])/g,
  23. /(WVVoU01HTkViM1pN|WVVoU01HTklUVFpNZ)(\w|=|\+|\/)*(?=[^\+=\w\/])/g,
  24. ]
  25. const regInvalid = /[^\w\+\/=]/;
  26.  
  27.  
  28. var Base64 = {
  29. _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  30. decode : function (input) {
  31. var output = "";
  32. var chr1, chr2, chr3;
  33. var enc1, enc2, enc3, enc4;
  34. var i = 0;
  35.  
  36. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  37.  
  38. while (i < input.length) {
  39. enc1 = this._keyStr.indexOf(input.charAt(i++));
  40. enc2 = this._keyStr.indexOf(input.charAt(i++));
  41. enc3 = this._keyStr.indexOf(input.charAt(i++));
  42. enc4 = this._keyStr.indexOf(input.charAt(i++));
  43.  
  44. chr1 = (enc1 << 2) | (enc2 >> 4);
  45. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  46. chr3 = ((enc3 & 3) << 6) | enc4;
  47.  
  48. output = output + String.fromCharCode(chr1);
  49.  
  50. if (enc3 != 64) {
  51. output = output + String.fromCharCode(chr2);
  52. }
  53. if (enc4 != 64) {
  54. output = output + String.fromCharCode(chr3);
  55. }
  56. }
  57.  
  58. output = Base64._utf8_decode(output);
  59. return output;
  60. },
  61. // private method for UTF-8 decoding
  62. _utf8_decode : function (utftext) {
  63. var string = "";
  64. var i = 0;
  65. var c = 0;
  66. var c1 = 0;
  67. var c2 = 0;
  68. var c3 = 0;
  69.  
  70. while ( i < utftext.length ) {
  71. c = utftext.charCodeAt(i);
  72. if (c < 128) {
  73. string += String.fromCharCode(c);
  74. i++;
  75. }
  76. else if((c > 191) && (c < 224)) {
  77. c2 = utftext.charCodeAt(i+1);
  78. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  79. i += 2;
  80. }
  81. else {
  82. c2 = utftext.charCodeAt(i+1);
  83. c3 = utftext.charCodeAt(i+2);
  84. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  85. i += 3;
  86. }
  87. }
  88. return string;
  89. }
  90. }
  91.  
  92. var hindex = 0; //total index
  93. const max_iter = 3; //max try decode iteration attamp, def:3
  94.  
  95. var lastSelected = document;
  96. var lastSelectedTime = Date.now();
  97.  
  98. function createLink(orig, index, url, depth) {
  99. return '<a href="' + url
  100. + '" target="_blank" rel="noreferrer">' + index.toString()
  101. + '번째 링크 (base64 깊이: ' + depth.toString()
  102. + ')</a>'
  103. + '<br>[ <a>' + orig.toString() + '</a> ]';
  104. }
  105.  
  106. function replacerGen(numIter) {
  107. return function(match) {
  108. try {
  109. return_f = ""; //return msg
  110. console.log(match)
  111. var converted = Base64.decode(match);
  112. for(var i=0; i<numIter; i++) {
  113. converted = Base64.decode(converted);
  114. }
  115. hindex++;
  116.  
  117. converted = decodeURI(encodeURI(converted).replaceAll('%00', '')); //remove invalid string - �
  118.  
  119. converted = converted.split(/\r?\n/);
  120.  
  121. console.log(converted)
  122. console.log(converted.length)
  123. if ((converted.length == 2 && converted[converted.length-1] == '') || converted.length <= 1) {
  124. return_f+=createLink(match, hindex, converted, numIter+1);
  125. } else if (converted.length > 1) {
  126. return_f+='[ ' + match.toString() + ' ]';
  127. nindex = 1;
  128. converted.forEach(function(k) {
  129. if (k != '') {
  130. console.log(k)
  131. return_f+='<br>' + createLink('링크 자동 분할 : ' + nindex.toString() + '번째', hindex, k, numIter+1);
  132. hindex++;
  133. nindex++;
  134. }
  135. });
  136. hindex--; //last components
  137. nindex--;
  138. return_f = '분할된 링크 총 ' + nindex + '개 ' + return_f;
  139. } else return_f+=createLink(match, hindex, converted, numIter+1);
  140.  
  141. return return_f
  142. } catch(e) {
  143. console.log(e);
  144. console.log('base64 변환 실패 : ' + match);
  145. }
  146. return '[base64 변환 실패 : ' + match + ']';
  147. }
  148. }
  149.  
  150. //function disabled
  151. function selClicked(event) {
  152. var sel = document.getSelection().toString();
  153. if (!sel.match(regInvalid)
  154. && sel.length >= 10
  155. && lastSelectedTime + 200 < Date.now()) {
  156. try {
  157. var converted = Base64.decode(sel);
  158. } catch (e) {
  159. return;
  160. } finally {
  161. this.innerHTML = this.innerHTML.replace(sel, converted);
  162. this.removeEventListener('click', selClicked);
  163. }
  164. }
  165. }
  166.  
  167. (function() {
  168. 'use strict';
  169.  
  170. var article = document.getElementsByClassName("article-content")[0];
  171. for(var i=0; i<max_iter; i++) {
  172. article.innerHTML = article.innerHTML.replaceAll(regArr[i], replacerGen(i));
  173. }
  174.  
  175. var comments = document.getElementsByClassName("list-area");
  176. if(comments.length != 0) {
  177. for(var i=0; i<max_iter; i++) {
  178. comments[0].innerHTML = comments[0].innerHTML.replaceAll(regArr[i], replacerGen(i));
  179. }
  180. }
  181. /*
  182. document.addEventListener('selectionchange', function() {
  183. var sel = document.getSelection().anchorNode;
  184. if(sel) {
  185. sel = sel.parentElement;
  186. if(sel != lastSelected) {
  187. lastSelected.removeEventListener('click', selClicked);
  188. sel.addEventListener('click', selClicked);
  189. lastSelected = sel;
  190. lastSelectedTime = Date.now();
  191. }
  192. }
  193. })*/
  194. })();