Arca base64 autodecoder

아카라이브 Base64 자동 복호화

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

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