Arca base64 autodecoder

아카라이브 Base64 자동 복호화

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

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