CookieCloud

CookieCloud的tampermonkey版本,目前仅支持上传cookie。

当前为 2024-09-25 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name CookieCloud
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-09-24
  5. // @description CookieCloud的tampermonkey版本,目前仅支持上传cookie。
  6. // @author tomato
  7. // @icon https://store-images.s-microsoft.com/image/apps.63473.a0ccb631-d5e7-422b-bcc7-c0405274114b.be044f83-1292-4e84-a65d-e0527d895863.05fc1666-519a-4d36-8b67-8110c70b45cc?mode=scale&h=64&q=90&w=64
  8. // @match *://*/*
  9. // @grant GM_cookie
  10. // @grant GM_xmlhttpRequest
  11. // @connect *
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js
  13. // @run-at document-end
  14. // @license MIT
  15. // ==/UserScript==
  16.  
  17. /* global $, jQuery, CryptoJS */
  18.  
  19.  
  20. (function() {
  21. 'use strict';
  22.  
  23. const configStoreKey = '_cookieCloudConfig';
  24.  
  25. async function init() {
  26. const btnContainer = document.createElement('section');
  27. const asyncBtn = document.createElement('button');
  28. const asyncConfigBtn = document.createElement('button');
  29. asyncBtn.innerText = '上传';
  30. asyncConfigBtn.innerText = '配置';
  31. const btnContainerStyles = {
  32. position: 'fixed',
  33. bottom: '200px',
  34. left: '20px',
  35. fontSize: '14px',
  36. zIndex: 1000,
  37. };
  38.  
  39. const btnStyles = {
  40. display: 'block',
  41. width: '50px',
  42. height: '50px',
  43. borderRadius: '50%',
  44. backgroundColor: '#87CEEB',
  45. border: 'none',
  46. color: '#fff',
  47. marginBottom: '10px',
  48. boxShadow: '0 4px 8px rgba(0, 0, 0, 0.3)'
  49. }
  50. Object.assign(btnContainer.style, btnContainerStyles);
  51. Object.assign(asyncBtn.style, btnStyles);
  52. Object.assign(asyncConfigBtn.style, btnStyles);
  53.  
  54. btnContainer.appendChild(asyncBtn);
  55. btnContainer.appendChild(asyncConfigBtn);
  56. document.body.appendChild(btnContainer);
  57.  
  58. asyncConfigBtn.onclick = function() {
  59. const modal = initConfigForm();
  60. document.body.appendChild(modal);
  61. }
  62. // 为按钮添加点击事件
  63. asyncBtn.onclick = async function(event) {
  64. event.stopPropagation();
  65.  
  66. const config = localStorage.getItem(configStoreKey);
  67. if (!config) {
  68. alert('请填写配置');
  69. return;
  70. };
  71. const {url, uuid, password, domain = location.host} = JSON.parse(config);
  72. if (!url) {
  73. alert('请填写服务器地址');
  74. return;
  75. };
  76. if (!uuid) {
  77. alert('请填写uuid');
  78. return;
  79. };
  80. if (!password) {
  81. alert('请填写密码');
  82. return;
  83. };
  84.  
  85. const cookies = await getCookie(domain);
  86. const encryptCookies = cookie_encrypt(uuid, password, cookies);
  87.  
  88. const payload = {
  89. uuid,
  90. encrypted: encryptCookies
  91. };
  92.  
  93. const res = await syncCookie(url, payload);
  94. try {
  95. const resData = JSON.parse(res.response)
  96. console.log('resData:', resData);
  97. if (resData.action === 'done') {
  98. alert('同步成功')
  99. } else {
  100. throw('错误')
  101. }
  102. } catch(e) {
  103. alert(String(e))
  104. }
  105. };
  106. }
  107.  
  108. function initConfigForm() {
  109. // 创建遮罩层
  110. const overlay = document.createElement('div');
  111. overlay.style.position = 'fixed';
  112. overlay.style.top = '0';
  113. overlay.style.left = '0';
  114. overlay.style.width = '100%';
  115. overlay.style.height = '100%';
  116. overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
  117. overlay.style.zIndex = '1001';
  118.  
  119. // 创建弹框(Modal)容器
  120. const modal = document.createElement('div');
  121. const modalStyles = {
  122. position: 'fixed',
  123. top: '50%',
  124. left: '50%',
  125. transform: 'translate(-50%, -50%)',
  126. width: '400px',
  127. backgroundColor: '#fff',
  128. padding: '20px',
  129. boxShadow: '0 4px 10px rgba(0, 0, 0, 0.3)',
  130. zIndex: '1000',
  131. borderRadius: '8px',
  132. };
  133. Object.assign(modal.style, modalStyles);
  134.  
  135. // 创建表单
  136. const form = document.createElement('form');
  137. const inputStyles = {
  138. width: '100%',
  139. padding: '8px',
  140. boxSizing: 'border-box',
  141. marginBottom: '10px'
  142. };
  143.  
  144. // 创建同步域名关键词·默认当前域名
  145. const domainEle = document.createElement('input');
  146. domainEle.type = 'text';
  147. domainEle.placeholder = '同步域名关键词·默认当前域名';
  148. Object.assign(domainEle.style, inputStyles);
  149.  
  150. // 创建输入框 服务器地址
  151. const urlEle = document.createElement('input');
  152. urlEle.type = 'text';
  153. urlEle.placeholder = '服务器地址';
  154. Object.assign(urlEle.style, inputStyles);
  155.  
  156. // 创建输入框 端对端加密密码
  157. const pwdEle = document.createElement('input');
  158. pwdEle.type = 'text';
  159. pwdEle.placeholder = '输入框 端对端加密密码';
  160. Object.assign(pwdEle.style, inputStyles);
  161.  
  162. // 创建输入框 用户KEY · UUID
  163. const uuieEle = document.createElement('input');
  164. uuieEle.type = 'text';
  165. uuieEle.placeholder = '用户KEY · UUID';
  166. Object.assign(uuieEle.style, inputStyles);
  167.  
  168. // 创建保存按钮
  169. const saveButton = document.createElement('button');
  170. saveButton.type = 'submit';
  171. saveButton.innerText = '保存';
  172. saveButton.style.width = '100%';
  173. saveButton.style.padding = '10px';
  174. saveButton.style.backgroundColor = '#87CEEB';
  175. saveButton.style.border = 'none';
  176. saveButton.style.color = '#fff';
  177. saveButton.style.cursor = 'pointer';
  178. saveButton.style.fontSize = '16px';
  179. saveButton.style.borderRadius = '4px';
  180.  
  181. const config = localStorage.getItem(configStoreKey);
  182. if (config) {
  183. const {url, uuid, password, domain = ''} = JSON.parse(config);
  184. urlEle.value = url;
  185. pwdEle.value = password;
  186. uuieEle.value = uuid;
  187. domainEle.value = domain;
  188. };
  189.  
  190. saveButton.onclick = function () {
  191. const configStr = JSON.stringify({
  192. url: urlEle.value,
  193. password: pwdEle.value,
  194. uuid: uuieEle.value,
  195. domain: domainEle.value
  196. });
  197. localStorage.setItem(configStoreKey, configStr);
  198. overlay.remove();
  199. }
  200. modal.onclick = function (event) {
  201. event.stopPropagation();
  202. }
  203. overlay.onclick = function () {
  204. overlay.remove();
  205. }
  206. // 将输入框和保存按钮添加到表单
  207. form.appendChild(domainEle);
  208. form.appendChild(urlEle);
  209. form.appendChild(pwdEle);
  210. form.appendChild(uuieEle);
  211. form.appendChild(saveButton);
  212.  
  213. // 将表单添加到弹框中
  214. modal.appendChild(form);
  215. overlay.appendChild(modal);
  216. return overlay;
  217. }
  218.  
  219. // 用aes对cookie进行加密
  220. function cookie_encrypt( uuid, password, cookies ) {
  221. const the_key = CryptoJS.MD5(uuid+'-'+password).toString().substring(0,16);
  222. const data_to_encrypt = JSON.stringify({"cookie_data":cookies,"update_time":new Date()});
  223. return CryptoJS.AES.encrypt(data_to_encrypt, the_key).toString();
  224. }
  225.  
  226. async function getCookie(domain) {
  227. return new Promise((res, rej) => {
  228. GM_cookie.list({}, function(cookies, error) {
  229. if (!error) {
  230. const ret_cookies = {};
  231. for( const cookie of cookies ) {
  232. if( cookie.domain?.includes(domain) ) {
  233. if (!ret_cookies[domain]) {
  234. ret_cookies[domain] = [cookie];
  235. } else {
  236. ret_cookies[domain].push(cookie);
  237. }
  238. }
  239. }
  240. res(ret_cookies);
  241. } else {
  242. console.error(error);
  243. rej(error)
  244. }
  245. });
  246. })
  247. }
  248. // 上传cookie
  249. async function syncCookie(url, body) {
  250. return new Promise((res, rej) => {
  251. GM_xmlhttpRequest({
  252. method: 'POST',
  253. url: url+'/update',
  254. data: JSON.stringify(body),
  255. headers: {
  256. 'Content-Type': 'application/json',
  257. },
  258. onload: function(response) {
  259. console.log('Response:', response.responseText);
  260. res(response);
  261. },
  262. onerror: function(error) {
  263. console.error('Error:', error);
  264. rej(error);
  265. }
  266. });
  267. })
  268. }
  269.  
  270. init();
  271. })();