CookieCloud

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

目前为 2024-09-25 提交的版本。查看 最新版本

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