work.ink bypasser

Automatically does work.ink steps.

  1. // ==UserScript==
  2. // @name work.ink bypasser
  3. // @namespace lemons
  4. // @match https://*.work.ink/*
  5. // @match https://workink.click/*
  6. // @match *://*/direct/?*
  7. // @grant none
  8. // @icon https://work.ink/favicon.ico
  9. // @license GPLv3.0-or-later
  10. // @version 1.0.6
  11. // @resource NOTYF_CSS https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.css
  12. // @require https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.js
  13. // @author lemons
  14. // @description Automatically does work.ink steps.
  15. // @noframes
  16. // @run-at document-end
  17. // @grant GM_getResourceText
  18. // @grant GM_addStyle
  19. // ==/UserScript==
  20.  
  21. const notyfCss = GM_getResourceText("NOTYF_CSS");
  22. GM_addStyle(notyfCss);
  23. const notyf = new Notyf({ duration: 5000 });
  24.  
  25. (async () => {
  26. if (window.location.hostname.includes("r.")) window.location.hostname = window.location.hostname.replace("r.", "");
  27. if (window.location.hostname === "work.ink") {
  28. const [encodedUserId, linkCustom] = decodeURIComponent(window.location.pathname.slice(1)).split("/").slice(-2);
  29. const BASE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  30. const loopTimes = encodedUserId.length;
  31. let decodedUserId = BASE.indexOf(encodedUserId[0]);
  32. for (let i = 1; i < loopTimes; i++) decodedUserId = 62 * decodedUserId + BASE.indexOf(encodedUserId[i]);
  33.  
  34. const payloads = {
  35. social: (url) => JSON.stringify({
  36. type: "c_social_started",
  37. payload: {
  38. url
  39. }
  40. }),
  41. readArticles: {
  42. 1: JSON.stringify({
  43. type: "c_monetization",
  44. payload: {
  45. type: "readArticles",
  46. payload: {
  47. event: "start"
  48. }
  49. }
  50. }),
  51. 2: JSON.stringify({
  52. type: "c_monetization",
  53. payload: {
  54. type: "readArticles",
  55. payload: {
  56. event: "closeClicked"
  57. }
  58. }
  59. })
  60. },
  61. browserExtension: {
  62. 1: JSON.stringify({
  63. type: "c_monetization",
  64. payload: {
  65. type: "browserExtension",
  66. payload: {
  67. event: "start"
  68. }
  69. }
  70. }),
  71. 2: (token) => JSON.stringify({
  72. type: "c_monetization",
  73. payload: {
  74. type: "browserExtension",
  75. payload: {
  76. event: "confirm",
  77. token
  78. }
  79. }
  80. })
  81. }
  82. }
  83.  
  84. WebSocket.prototype.oldSendImpl = WebSocket.prototype.send;
  85. WebSocket.prototype.send =
  86. function (data) {
  87. this.oldSendImpl(data);
  88. this.addEventListener(
  89. "message",
  90. async (e) => {
  91. const sleep = ms => new Promise(r => setTimeout(r, ms));
  92. const data = JSON.parse(e.data);
  93. if (data.error) return;
  94. const payload = data.payload;
  95.  
  96. switch (data.type) {
  97. case "s_link_info":
  98. notyf.success("got link info")
  99. if (payload.socials) socials.push(...payload.socials);
  100. const monetizationTypes = ["readArticles", "browserExtension"];
  101. for (const type of monetizationTypes) {
  102. if (payload.monetizationScript.includes(type)) {
  103. activeMonetizationTypes.push(type)
  104. }
  105. }
  106. break;
  107. case "s_start_recaptcha_check":
  108. this.oldSendImpl(payloads.captcha);
  109. break;
  110. case "s_recaptcha_okay":
  111. if (socials.length) {
  112. for (const [index, social] of socials.entries()) {
  113. notyf.success(`performing social #${index+1}`)
  114. this.oldSendImpl(payloads.social(social.url));
  115. await sleep(3 * 1000);
  116. }
  117. }
  118.  
  119. if (activeMonetizationTypes.length) {
  120. for (const type of activeMonetizationTypes) {
  121. switch (type) {
  122. case "readArticles":
  123. notyf.success("reading articles...")
  124. this.oldSendImpl(payloads.readArticles["1"]);
  125. this.oldSendImpl(payloads.readArticles["2"]);
  126. break;
  127. case "browserExtension":
  128. notyf.success("skipping browser extension step")
  129. if (activeMonetizationTypes.includes("readArticles")) await sleep(11 * 1000);
  130. this.oldSendImpl(payloads.browserExtension["1"])
  131. break;
  132. }
  133. }
  134. }
  135. break;
  136. case "s_monetization":
  137. if (payload.type !== "browserExtension") break;
  138. this.oldSendImpl(payloads.browserExtension["2"](payload.payload.token))
  139. break;
  140. case "s_link_destination":
  141. notyf.success("done!")
  142. const url = new URL(payload.url);
  143. localStorage.clear(window.location.href);
  144. if (url.searchParams.has("duf")) {
  145. window.location.href = window.atob(url.searchParams.get("duf").split("").reverse().join(""))
  146. };
  147. window.location.href = payload.url;
  148. break;
  149. }
  150. },
  151. false
  152. );
  153. this.send =
  154. function (data) {
  155. this.oldSendImpl(data);
  156. };
  157. }
  158. notyf.success("patched websocket")
  159. let socials = [];
  160. let activeMonetizationTypes = [];
  161. } else if (window.location.hostname == "workink.click") {
  162. const uuid = new URLSearchParams(window.location.search).get("t")
  163. fetch(`https://redirect-api.work.ink/externalPopups/${uuid}/pageOpened`);
  164. await new Promise(r => setTimeout(r, 11 * 1000));
  165. const { destination } = await fetch(`https://redirect-api.work.ink/externalPopups/${uuid}/destination`).then(r => r.json());
  166. const url = new URL(destination);
  167. if (url.searchParams.has("duf")) {
  168. window.location.href = window.atob(url.searchParams.get("duf").split("").reverse().join(""))
  169. };
  170. window.location.href = destination;
  171. notyf.success("wait 11 seconds")
  172. } else {
  173. if (new URL(window.location.href).searchParams.has("duf")) {
  174. var link = document.createElement("a");
  175. link.referrerPolicy = "no-referrer";
  176. link.rel = "noreferrer";
  177.  
  178. link.href = window.atob(new URL(window.location.href).searchParams.get("duf").split("").reverse().join(""));
  179. link.click();
  180. };
  181. }
  182. })();