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.151a
  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. */
  27.  
  28. //max attempt decode depth, default:3
  29. const max_iter = 3;
  30. //regex prefix - common
  31. const regArr = [
  32. /(aHR0cDovL|aHR0cHM6Ly)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 1 time
  33. /(YUhSMGNEb3ZM|YUhSMGNITTZMe)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 2 time
  34. /(WVVoU01HTkViM1pN|WVVoU01HTklUVFpNZ)(\w|=|\+|\/)*(?=[^\+=\w\/])/g, //encoding 3 time
  35. ];
  36. //regex prefix - drag
  37. const regInvalid = /[^\w\+\/=]/;
  38.  
  39. //auto add padding - add '=' padding in base64 encoded string
  40. function base64AddPadding(str) {
  41. return str + Array((4 - str.length % 4) % 4 + 1).join('=');
  42. }
  43.  
  44. //base64 decode
  45. var Base64 = {
  46. _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  47. decode : function (input) {
  48. var output = "";
  49. var chr1, chr2, chr3;
  50. var enc1, enc2, enc3, enc4;
  51. var i = 0;
  52.  
  53. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  54.  
  55. while (i < input.length) {
  56. enc1 = this._keyStr.indexOf(input.charAt(i++));
  57. enc2 = this._keyStr.indexOf(input.charAt(i++));
  58. enc3 = this._keyStr.indexOf(input.charAt(i++));
  59. enc4 = this._keyStr.indexOf(input.charAt(i++));
  60.  
  61. chr1 = (enc1 << 2) | (enc2 >> 4);
  62. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  63. chr3 = ((enc3 & 3) << 6) | enc4;
  64.  
  65. output = output + String.fromCharCode(chr1);
  66.  
  67. if (enc3 != 64) {
  68. output = output + String.fromCharCode(chr2);
  69. }
  70. if (enc4 != 64) {
  71. output = output + String.fromCharCode(chr3);
  72. }
  73. }
  74.  
  75. output = Base64._utf8_decode(output);
  76. return output;
  77. },
  78. // private method for UTF-8 decoding
  79. _utf8_decode : function (utftext) {
  80. var string = "";
  81. var i = 0;
  82. var c = 0;
  83. var c1 = 0;
  84. var c2 = 0;
  85. var c3 = 0;
  86.  
  87. while ( i < utftext.length ) {
  88. c = utftext.charCodeAt(i);
  89. if (c < 128) {
  90. string += String.fromCharCode(c);
  91. i++;
  92. }
  93. else if((c > 191) && (c < 224)) {
  94. c2 = utftext.charCodeAt(i+1);
  95. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  96. i += 2;
  97. }
  98. else {
  99. c2 = utftext.charCodeAt(i+1);
  100. c3 = utftext.charCodeAt(i+2);
  101. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  102. i += 3;
  103. }
  104. }
  105. return string;
  106. }
  107. };
  108.  
  109. var hindex = 0; //total decode count
  110.  
  111. //drag function comparison
  112. var lastSelected = document;
  113. var lastSelectedTime = Date.now();
  114.  
  115. //create link each components
  116. function createLink(orig, index, url, depth) {
  117. //n번째 링크 (base64 깊이: 0) [ ABCDEF= ]
  118. return '<a href="' + url + '" title="' + url + ' (새 창으로 열기)" target="_blank" rel="external nofollow noopener noreferrer">' + index.toString() + '번째 링크 (base64 깊이: ' + depth.toString() + ')</a> [ <code>' + orig.toString() + '</code> ]';
  119. }
  120.  
  121. //decode & generate
  122. function replacerGen(numIter) {
  123. return function(source) {
  124. try {
  125. return_f = ""; //return msg
  126. console.log(source); //source
  127.  
  128. //decode
  129. var converted = Base64.decode(base64AddPadding(source));
  130. //attempt to decode nested base64 encoded string
  131. for(var i=0; i<numIter; i++) {
  132. converted = Base64.decode(base64AddPadding(converted));
  133. }
  134. hindex++;
  135.  
  136. //remove invalid string - �
  137. converted = decodeURI(encodeURI(converted).replaceAll('%00', ''));
  138.  
  139. //split by new line
  140. converted = converted.split(/\r?\n/);
  141. //single component
  142. if (converted.length == 2 && converted[converted.length-1] == '') {
  143. return_f += createLink(source, hindex, converted[0], numIter+1);
  144. //multiple component
  145. } else if (converted.length > 1) {
  146. return_f += '[ ' + source.toString() + ' ]';
  147. nindex = 1;
  148. converted.forEach(function(j) {
  149. if (j != '') {
  150. return_f += '<br>' + createLink('링크 자동 분할 : ' + nindex.toString() + '번째', hindex, j, numIter+1);
  151. hindex++;
  152. nindex++;
  153. }
  154. });
  155. //last components
  156. hindex--;
  157. nindex--;
  158.  
  159. return_f = '분할된 링크 총 ' + nindex + '개 ' + return_f;
  160. } else return_f += createLink(source, hindex, converted, numIter+1);
  161. return return_f;
  162. } catch(e) {
  163. console.log(e);
  164. console.log('base64 변환 실패 : ' + source);
  165. }
  166. return '[ base64 변환 실패 : ' + source + ' ]';
  167. };
  168. }
  169.  
  170. //user drag event
  171. //function disabled
  172. function selClicked(event) {
  173. var sel = document.getSelection().toString();
  174. if (!sel.match(regInvalid) && sel.length >= 10 && lastSelectedTime + 200 < Date.now()) {
  175. try {
  176. var converted = decodeURI(encodeURI(Base64.decode(base64AddPadding(sel))).replaceAll('%00', ''));
  177. this.innerHTML = this.innerHTML.replace(sel, converted);
  178. this.removeEventListener('click', selClicked);
  179. } catch (e) {
  180. return;
  181. } finally {
  182. }
  183. }
  184. }
  185.  
  186. //main
  187. (function() {
  188. 'use strict';
  189.  
  190. //article
  191. var article = document.getElementsByClassName("article-content")[0];
  192. for(var i=0; i<max_iter; i++) {
  193. article.innerHTML = article.innerHTML.replaceAll(regArr[i], replacerGen(i));
  194. }
  195.  
  196. //comment
  197. var comments = document.getElementsByClassName("list-area");
  198. if(comments.length != 0) {
  199. for(var j=0; j<max_iter; j++) {
  200. comments[0].innerHTML = comments[0].innerHTML.replaceAll(regArr[j], replacerGen(j));
  201. }
  202. }
  203.  
  204. /*
  205. //user drag
  206. document.addEventListener('selectionchange', function() {
  207. var sel = document.getSelection().anchorNode;
  208. if(sel) {
  209. sel = sel.parentElement;
  210. if(sel != lastSelected) {
  211. lastSelected.removeEventListener('click', selClicked);
  212. sel.addEventListener('click', selClicked);
  213. lastSelected = sel;
  214. lastSelectedTime = Date.now();
  215. }
  216. }
  217. })
  218. */
  219.  
  220. })();