From bd1f6af567aced3c2c83c0bc54080f9a1b48819a Mon Sep 17 00:00:00 2001 From: Mousad Date: Tue, 26 May 2026 23:12:54 +0300 Subject: [PATCH 1/3] feat: add API retry logic with exponential backoff and topic tags extraction --- .gitignore | 7 +++++- README.md | 4 ++++ leetcode_export/leetcode.py | 34 +++++++++++++++++++++-------- leetcode_export/leetcode_graphql.py | 5 +++++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1e77861..97cd716 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,9 @@ dmypy.json # IDE folders .vscode -.idea \ No newline at end of file +.idea + +# Sensitive Information +leetcode_cookies.txt +problem_cache.json +*.session \ No newline at end of file diff --git a/README.md b/README.md index ca8f135..abbd38d 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ Before running the script, make sure that python3 is installed in your system. If you prefer, you can use the Docker image to download LeetCode submissions. For more information read the section [Docker Image](#docker-image). +### ✨ New Features Added +- **API Resilience**: Added retry logic with exponential backoff for GraphQL queries and submission requests to prevent crashes on network timeouts or rate limits. +- **Topic Tags Export**: Problems now extract and expose `topicTags` for categorizing solutions by LeetCode topics. + ## 🏁 Getting started ### Download `leetcode-export` diff --git a/leetcode_export/leetcode.py b/leetcode_export/leetcode.py index 0fe0349..3e905fd 100644 --- a/leetcode_export/leetcode.py +++ b/leetcode_export/leetcode.py @@ -124,12 +124,19 @@ def get_problem_statement(self, slug: str) -> Problem: :param slug: problem identifier :return: Problem """ - response = self.session.post(GRAPHQL_URL, json=question_detail_json(slug)) - if "data" in response.json() and "question" in response.json()["data"]: - problem_dict = dict_camelcase_to_snakecase( - response.json()["data"]["question"] - ) - return Problem.from_dict(problem_dict) + for attempt in range(5): + try: + response = self.session.post(GRAPHQL_URL, json=question_detail_json(slug), timeout=20) + if "data" in response.json() and "question" in response.json()["data"]: + problem_dict = dict_camelcase_to_snakecase( + response.json()["data"]["question"] + ) + return Problem.from_dict(problem_dict) + break + except requests.exceptions.RequestException as e: + logging.warning(f"GraphQL request failed: {e}. Retrying in {5 * (attempt + 1)} seconds...") + sleep(5 * (attempt + 1)) + return None def get_submissions(self) -> Iterator[Submission]: """ @@ -148,9 +155,18 @@ def get_submissions(self) -> Iterator[Submission]: and response_json["has_next"] ): logging.debug(f"Exporting submissions from {current} to {current + 20}") - response = self.session.get(SUBMISSIONS_API_URL.format(current, 20)) - logging.debug(response.content) - response_json = response.json() + for attempt in range(5): + try: + response = self.session.get(SUBMISSIONS_API_URL.format(current, 20), timeout=20) + logging.debug(response.content) + response_json = response.json() + break + except requests.exceptions.RequestException as e: + logging.warning(f"Request failed: {e}. Retrying in {5 * (attempt + 1)} seconds...") + sleep(5 * (attempt + 1)) + else: + logging.error("Max retries exceeded for fetching submissions.") + break if "submissions_dump" in response_json: for submission_dict in response_json["submissions_dump"]: submission_dict["runtime"] = submission_dict["runtime"].replace( diff --git a/leetcode_export/leetcode_graphql.py b/leetcode_export/leetcode_graphql.py index 2886f7c..95f50e6 100644 --- a/leetcode_export/leetcode_graphql.py +++ b/leetcode_export/leetcode_graphql.py @@ -14,6 +14,7 @@ class Problem: title: str title_slug: str content: str + topic_tags: list def question_detail_json(slug): @@ -28,6 +29,10 @@ def question_detail_json(slug): title titleSlug content + topicTags { + name + slug + } } }""", } From 225952201abab7490613e294ed27f3016f3aae27 Mon Sep 17 00:00:00 2001 From: Mousad Date: Sun, 31 May 2026 09:17:10 +0300 Subject: [PATCH 2/3] docs: add full automation tutorial and chrome extension --- README.md | 50 ++++++++++++++++++ chrome-extension/background.js | 84 +++++++++++++++++++++++++++++++ chrome-extension/manifest.json | 21 ++++++++ chrome-extension/nacl-util.min.js | 1 + chrome-extension/nacl.min.js | 1 + chrome-extension/popup.html | 32 ++++++++++++ chrome-extension/popup.js | 27 ++++++++++ chrome-extension/sealedbox.js | 1 + 8 files changed, 217 insertions(+) create mode 100644 chrome-extension/background.js create mode 100644 chrome-extension/manifest.json create mode 100644 chrome-extension/nacl-util.min.js create mode 100644 chrome-extension/nacl.min.js create mode 100644 chrome-extension/popup.html create mode 100644 chrome-extension/popup.js create mode 100644 chrome-extension/sealedbox.js diff --git a/README.md b/README.md index abbd38d..61d9183 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,56 @@ extension: str Default submission filename template: `${date_formatted} - ${status_display} - runtime ${runtime} - memory ${memory}.${extension}` + +## 🚀 Full Automation: Daily GitHub Sync + +You can fully automate your LeetCode backup to a separate GitHub repository using **GitHub Actions** and the provided **Chrome Extension**. + +### 1. Create your Solutions Repository +1. Create a new private GitHub repository (e.g., `LeetCode-Solutions`). +2. Create a file `.github/workflows/sync.yml` with the following content: + +```yaml +name: Daily LeetCode Sync +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + sync: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + - run: | + pip install git+https://github.com/MohamedMousad/leetcode-export.git@feature/api-retry-and-tags + - env: + LEETCODE_COOKIE: ${{ secrets.LEETCODE_COOKIE }} + run: | + python -m leetcode_export --folder . + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "Auto-sync: Daily update" || echo "No changes" + git push origin main +``` + +### 2. Set Up the Chrome Extension +Because LeetCode cookies change, we provide a Chrome Extension that automatically syncs your active session cookie to your GitHub repository securely as a secret. +1. Generate a **GitHub Personal Access Token (Classic)** with `repo` and `workflow` permissions. +2. Open Chrome and navigate to `chrome://extensions/`. +3. Enable **Developer mode** (top right corner). +4. Click **Load unpacked** and select the `chrome-extension` folder found in this repository. +5. Click the extension icon in your browser toolbar, paste your PAT and repository name (e.g., `YourUser/LeetCode-Solutions`), and click **Save**. +6. Whenever you log into LeetCode, click **Push Cookie to GitHub Now** in the extension to automatically securely update the `LEETCODE_COOKIE` secret in your repository. + +Your GitHub action will now run seamlessly every day! + ## Special mentions Thanks to [skygragon](https://github.com/skygragon) for diff --git a/chrome-extension/background.js b/chrome-extension/background.js new file mode 100644 index 0000000..8268f98 --- /dev/null +++ b/chrome-extension/background.js @@ -0,0 +1,84 @@ +importScripts('nacl.min.js', 'nacl-util.min.js', 'sealedbox.js'); + +const SECRET_NAME = "LEETCODE_COOKIE"; + +async function updateGitHubSecret() { + try { + const data = await chrome.storage.local.get(['github_token', 'github_repo']); + if (!data.github_token || !data.github_repo) { + return {status: "error", msg: "No GitHub token or repo configured."}; + } + + const [owner, repo] = data.github_repo.trim().split('/'); + if (!owner || !repo) return {status: "error", msg: "Invalid repo format. Use owner/repo."}; + + const cookies = await chrome.cookies.getAll({ domain: "leetcode.com" }); + if (cookies.length === 0) return {status: "error", msg: "No cookies found for leetcode.com!"}; + + let cookieStr = cookies.map(c => c.name + "=" + c.value).join("; "); + if (!cookieStr.includes("LEETCODE_SESSION")) { + return {status: "error", msg: "No LEETCODE_SESSION found. Are you logged in?"}; + } + + const keyRes = await fetch(`https://api.github.com/repos/${owner}/${repo}/actions/secrets/public-key`, { + headers: { + "Accept": "application/vnd.github+json", + "Authorization": `Bearer ${data.github_token.trim()}`, + "X-GitHub-Api-Version": "2022-11-28" + } + }); + + if (!keyRes.ok) { + const errTxt = await keyRes.text(); + return {status: "error", msg: `Failed to fetch public key. Status: ${keyRes.status}. ${errTxt}`}; + } + const keyData = await keyRes.json(); + + const messageBytes = nacl.util.decodeUTF8(cookieStr); + const keyBytes = nacl.util.decodeBase64(keyData.key); + + const encryptedBytes = sealedBox.seal(messageBytes, keyBytes); + const encryptedBase64 = nacl.util.encodeBase64(encryptedBytes); + + const uploadRes = await fetch(`https://api.github.com/repos/${owner}/${repo}/actions/secrets/${SECRET_NAME}`, { + method: "PUT", + headers: { + "Accept": "application/vnd.github+json", + "Authorization": `Bearer ${data.github_token.trim()}`, + "X-GitHub-Api-Version": "2022-11-28", + "Content-Type": "application/json" + }, + body: JSON.stringify({ + encrypted_value: encryptedBase64, + key_id: keyData.key_id + }) + }); + + if (uploadRes.ok || uploadRes.status === 201 || uploadRes.status === 204) { + chrome.storage.local.set({ last_sync: new Date().toLocaleString() }); + return {status: "ok", msg: "Success!"}; + } else { + const errTxt = await uploadRes.text(); + return {status: "error", msg: `Failed to upload secret. Status: ${uploadRes.status}. ${errTxt}`}; + } + } catch (e) { + return {status: "error", msg: "Exception: " + e.message}; + } +} + +// Run when alarm fires +chrome.alarms.create("syncAlarm", { periodInMinutes: 60 * 12 }); // Every 12 hours +chrome.alarms.onAlarm.addListener((alarm) => { + if (alarm.name === "syncAlarm") { + updateGitHubSecret(); + } +}); + +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === "sync_now") { + updateGitHubSecret().then((result) => { + sendResponse(result); + }); + return true; // Keep message channel open for async response + } +}); diff --git a/chrome-extension/manifest.json b/chrome-extension/manifest.json new file mode 100644 index 0000000..67835f9 --- /dev/null +++ b/chrome-extension/manifest.json @@ -0,0 +1,21 @@ +{ + "manifest_version": 3, + "name": "LeetCode Auto-Sync", + "version": "1.0", + "description": "Automatically keeps your LeetCode cookies updated as a GitHub Action Secret.", + "permissions": [ + "storage", + "alarms", + "cookies" + ], + "host_permissions": [ + "https://leetcode.com/*", + "https://api.github.com/*" + ], + "background": { + "service_worker": "background.js" + }, + "action": { + "default_popup": "popup.html" + } +} diff --git a/chrome-extension/nacl-util.min.js b/chrome-extension/nacl-util.min.js new file mode 100644 index 0000000..0426742 --- /dev/null +++ b/chrome-extension/nacl-util.min.js @@ -0,0 +1 @@ +!function(e,n){"use strict";"undefined"!=typeof module&&module.exports?module.exports=n():(e.nacl||(e.nacl={}),e.nacl.util=n())}(this,function(){"use strict";var e={};function o(e){if(!/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test(e))throw new TypeError("invalid encoding")}return e.decodeUTF8=function(e){if("string"!=typeof e)throw new TypeError("expected string");var n,r=unescape(encodeURIComponent(e)),t=new Uint8Array(r.length);for(n=0;n>>32-n}function b(r,n){var e=255&r[n+3];return(e=(e=e<<8|255&r[n+2])<<8|255&r[n+1])<<8|255&r[n+0]}function B(r,n){var e=r[n]<<24|r[n+1]<<16|r[n+2]<<8|r[n+3],t=r[n+4]<<24|r[n+5]<<16|r[n+6]<<8|r[n+7];return new m(e,t)}function p(r,n,e){var t;for(t=0;t<4;t++)r[n+t]=255&e,e>>>=8}function S(r,n,e){r[n]=e.hi>>24&255,r[n+1]=e.hi>>16&255,r[n+2]=e.hi>>8&255,r[n+3]=255&e.hi,r[n+4]=e.lo>>24&255,r[n+5]=e.lo>>16&255,r[n+6]=e.lo>>8&255,r[n+7]=255&e.lo}function u(r,n,e,t,o){var i,a=0;for(i=0;i>>8)-1}function A(r,n,e,t){return u(r,n,e,t,16)}function _(r,n,e,t){return u(r,n,e,t,32)}function U(r,n,e,t,o){var i,a,f,u=new Uint32Array(16),c=new Uint32Array(16),w=new Uint32Array(16),y=new Uint32Array(4);for(i=0;i<4;i++)c[5*i]=b(t,4*i),c[1+i]=b(e,4*i),c[6+i]=b(n,4*i),c[11+i]=b(e,16+4*i);for(i=0;i<16;i++)w[i]=c[i];for(i=0;i<20;i++){for(a=0;a<4;a++){for(f=0;f<4;f++)y[f]=c[(5*a+4*f)%16];for(y[1]^=h(y[0]+y[3]|0,7),y[2]^=h(y[1]+y[0]|0,9),y[3]^=h(y[2]+y[1]|0,13),y[0]^=h(y[3]+y[2]|0,18),f=0;f<4;f++)u[4*a+(a+f)%4]=y[f]}for(f=0;f<16;f++)c[f]=u[f]}if(o){for(i=0;i<16;i++)c[i]=c[i]+w[i]|0;for(i=0;i<4;i++)c[5*i]=c[5*i]-b(t,4*i)|0,c[6+i]=c[6+i]-b(n,4*i)|0;for(i=0;i<4;i++)p(r,4*i,c[5*i]),p(r,16+4*i,c[6+i])}else for(i=0;i<16;i++)p(r,4*i,c[i]+w[i]|0)}function E(r,n,e,t){U(r,n,e,t,!1)}function x(r,n,e,t){return U(r,n,e,t,!0),0}var d=new Uint8Array([101,120,112,97,110,100,32,51,50,45,98,121,116,101,32,107]);function K(r,n,e,t,o,i,a){var f,u,c=new Uint8Array(16),w=new Uint8Array(64);if(!o)return 0;for(u=0;u<16;u++)c[u]=0;for(u=0;u<8;u++)c[u]=i[u];for(;64<=o;){for(E(w,c,a,d),u=0;u<64;u++)r[n+u]=(e?e[t+u]:0)^w[u];for(f=1,u=8;u<16;u++)f=f+(255&c[u])|0,c[u]=255&f,f>>>=8;o-=64,n+=64,e&&(t+=64)}if(0>>=8}var z=new Uint32Array([5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,252]);function R(r,n,e,t,o,i){var a,f,u,c,w=new Uint32Array(17),y=new Uint32Array(17),l=new Uint32Array(17),s=new Uint32Array(17),h=new Uint32Array(17);for(u=0;u<17;u++)y[u]=l[u]=0;for(u=0;u<16;u++)y[u]=i[u];for(y[3]&=15,y[4]&=252,y[7]&=15,y[8]&=252,y[11]&=15,y[12]&=252,y[15]&=15;0>>=8;for(c=c+l[16]|0,l[16]=3&c,c=5*(c>>>2)|0,u=0;u<16;u++)c=c+l[u]|0,l[u]=255&c,c>>>=8;c=c+l[16]|0,l[16]=c}for(u=0;u<17;u++)h[u]=l[u];for(k(l,z),a=0|-(l[16]>>>7),u=0;u<17;u++)l[u]^=a&(h[u]^l[u]);for(u=0;u<16;u++)s[u]=i[u+16];for(s[16]=0,k(l,s),u=0;u<16;u++)r[n+u]=l[u];return 0}function P(r,n,e,t,o,i){var a=new Uint8Array(16);return R(a,0,e,t,o,i),A(r,n,a,0)}function M(r,n,e,t,o){var i;if(e<32)return-1;for(T(r,0,n,0,e,t,o),R(r,16,r,32,e-32,r),i=0;i<16;i++)r[i]=0;return 0}function N(r,n,e,t,o){var i,a=new Uint8Array(32);if(e<32)return-1;if(L(a,0,32,t,o),0!==P(n,16,n,32,e-32,a))return-1;for(T(r,0,n,0,e,t,o),i=0;i<32;i++)r[i]=0;return 0}function O(r,n){var e;for(e=0;e<16;e++)r[e]=0|n[e]}function C(r){var n,e;for(e=0;e<16;e++)r[e]+=65536,n=Math.floor(r[e]/65536),r[(e+1)*(e<15?1:0)]+=n-1+37*(n-1)*(15===e?1:0),r[e]-=65536*n}function F(r,n,e){for(var t,o=~(e-1),i=0;i<16;i++)t=o&(r[i]^n[i]),r[i]^=t,n[i]^=t}function Z(r,n){var e,t,o,i=v(),a=v();for(e=0;e<16;e++)a[e]=n[e];for(C(a),C(a),C(a),t=0;t<2;t++){for(i[0]=a[0]-65517,e=1;e<15;e++)i[e]=a[e]-65535-(i[e-1]>>16&1),i[e-1]&=65535;i[15]=a[15]-32767-(i[14]>>16&1),o=i[15]>>16&1,i[14]&=65535,F(a,i,1-o)}for(e=0;e<16;e++)r[2*e]=255&a[e],r[2*e+1]=a[e]>>8}function G(r,n){var e=new Uint8Array(32),t=new Uint8Array(32);return Z(e,r),Z(t,n),_(e,0,t,0)}function q(r){var n=new Uint8Array(32);return Z(n,r),1&n[0]}function D(r,n){var e;for(e=0;e<16;e++)r[e]=n[2*e]+(n[2*e+1]<<8);r[15]&=32767}function I(r,n,e){var t;for(t=0;t<16;t++)r[t]=n[t]+e[t]|0}function V(r,n,e){var t;for(t=0;t<16;t++)r[t]=n[t]-e[t]|0}function X(r,n,e){var t,o,i=new Float64Array(31);for(t=0;t<31;t++)i[t]=0;for(t=0;t<16;t++)for(o=0;o<16;o++)i[t+o]+=n[t]*e[o];for(t=0;t<15;t++)i[t]+=38*i[t+16];for(t=0;t<16;t++)r[t]=i[t];C(r),C(r)}function j(r,n){X(r,n,n)}function H(r,n){var e,t=v();for(e=0;e<16;e++)t[e]=n[e];for(e=253;0<=e;e--)j(t,t),2!==e&&4!==e&&X(t,t,n);for(e=0;e<16;e++)r[e]=t[e]}function J(r,n){var e,t=v();for(e=0;e<16;e++)t[e]=n[e];for(e=250;0<=e;e--)j(t,t),1!==e&&X(t,t,n);for(e=0;e<16;e++)r[e]=t[e]}function Q(r,n,e){var t,o,i=new Uint8Array(32),a=new Float64Array(80),f=v(),u=v(),c=v(),w=v(),y=v(),l=v();for(o=0;o<31;o++)i[o]=n[o];for(i[31]=127&n[31]|64,i[0]&=248,D(a,e),o=0;o<16;o++)u[o]=a[o],w[o]=f[o]=c[o]=0;for(f[0]=w[0]=1,o=254;0<=o;--o)F(f,u,t=i[o>>>3]>>>(7&o)&1),F(c,w,t),I(y,f,c),V(f,f,c),I(c,u,w),V(u,u,w),j(w,y),j(l,f),X(f,c,f),X(c,u,y),I(y,f,c),V(f,f,c),j(u,f),V(c,w,l),X(f,c,g),I(f,f,w),X(c,c,f),X(f,w,l),X(w,u,a),j(u,y),F(f,u,t),F(c,w,t);for(o=0;o<16;o++)a[o+16]=f[o],a[o+32]=c[o],a[o+48]=u[o],a[o+64]=w[o];var s=a.subarray(32),h=a.subarray(16);return H(s,s),X(h,h,s),Z(r,h),0}function W(r,n){return Q(r,n,e)}function $(r,n){return a(n,32),W(r,n)}function rr(r,n,e){var t=new Uint8Array(32);return Q(t,e,n),x(r,o,t,d)}var nr=M,er=N;function tr(){var r,n,e,t=0,o=0,i=0,a=0,f=65535;for(e=0;e>>16,i+=(n=arguments[e].hi)&f,a+=n>>>16;return new m((i+=(o+=t>>>16)>>>16)&f|(a+=i>>>16)<<16,t&f|o<<16)}function or(r,n){return new m(r.hi>>>n,r.lo>>>n|r.hi<<32-n)}function ir(){var r,n=0,e=0;for(r=0;r>>n|r.lo<>>n|r.hi<>>n|r.hi<>>n|r.lo<>(7&o)&1),yr(n,r),yr(r,r),lr(r,n,t)}function vr(r,n){var e=[v(),v(),v(),v()];O(e[0],t),O(e[1],f),O(e[2],w),X(e[3],t,f),hr(r,e,n)}function gr(r,n,e){var t,o=new Uint8Array(64),i=[v(),v(),v(),v()];for(e||a(n,32),wr(o,n,32),o[0]&=248,o[31]&=127,o[31]|=64,vr(i,o),sr(r,i),t=0;t<32;t++)n[t+32]=r[t];return 0}var br=new Float64Array([237,211,245,92,26,99,18,88,214,156,247,162,222,249,222,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16]);function pr(r,n){var e,t,o,i;for(t=63;32<=t;--t){for(e=0,o=t-32,i=t-12;o>4)*br[o],e=n[o]>>8,n[o]&=255;for(o=0;o<32;o++)n[o]-=e*br[o];for(t=0;t<32;t++)n[t+1]+=n[t]>>8,r[t]=255&n[t]}function Ar(r){var n,e=new Float64Array(64);for(n=0;n<64;n++)e[n]=r[n];for(n=0;n<64;n++)r[n]=0;pr(r,e)}function _r(r,n,e,t){var o,i,a=new Uint8Array(64),f=new Uint8Array(64),u=new Uint8Array(64),c=new Float64Array(64),w=[v(),v(),v(),v()];wr(a,t,32),a[0]&=248,a[31]&=127,a[31]|=64;var y=e+64;for(o=0;o>7&&V(r[0],c,r[0]),X(r[3],r[0],r[1])}(u,t))return-1;for(o=0;o + + + + + +

LeetCode Auto-Sync

+ + + + + + + + + + +

+ + + + diff --git a/chrome-extension/popup.js b/chrome-extension/popup.js new file mode 100644 index 0000000..608cffc --- /dev/null +++ b/chrome-extension/popup.js @@ -0,0 +1,27 @@ +document.addEventListener('DOMContentLoaded', () => { + chrome.storage.local.get(['github_token', 'github_repo', 'last_sync'], (res) => { + if (res.github_token) document.getElementById('pat').value = res.github_token; + if (res.github_repo) document.getElementById('repo').value = res.github_repo; + if (res.last_sync) document.getElementById('status').innerText = "Last sync: " + res.last_sync; + }); + + document.getElementById('save').addEventListener('click', () => { + chrome.storage.local.set({ + github_token: document.getElementById('pat').value, + github_repo: document.getElementById('repo').value + }, () => { + document.getElementById('status').innerText = "Settings saved! Extension is ready."; + }); + }); + + document.getElementById('sync').addEventListener('click', () => { + document.getElementById('status').innerText = "Fetching cookie and pushing to GitHub..."; + chrome.runtime.sendMessage({ action: "sync_now" }, (res) => { + if (res && res.status === "ok") { + document.getElementById('status').innerText = "Success! GitHub Secret Updated. \nYour daily GitHub Action will now run flawlessly."; + } else { + document.getElementById('status').innerText = "Error: " + (res ? res.msg : "Unknown error"); + } + }); + }); +}); diff --git a/chrome-extension/sealedbox.js b/chrome-extension/sealedbox.js new file mode 100644 index 0000000..193d37d --- /dev/null +++ b/chrome-extension/sealedbox.js @@ -0,0 +1 @@ +!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n(require("nacl"),require("Object")):"function"==typeof define&&define.amd?define(["nacl","Object"],n):"object"==typeof exports?exports.sealedBox=n(require("nacl"),require("Object")):e.sealedBox=n(e.nacl,e.Object)}(self,function(e,n){return function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=3)}([function(n,t){n.exports=e},function(e,n,t){var r=t(2);function o(e,n,t){var r=e[n]+e[t],o=e[n+1]+e[t+1];r>=4294967296&&o++,e[n]=r,e[n+1]=o}function a(e,n,t,r){var o=e[n]+t;t<0&&(o+=4294967296);var a=e[n+1]+r;o>=4294967296&&a++,e[n]=o,e[n+1]=a}function u(e,n){return e[n]^e[n+1]<<8^e[n+2]<<16^e[n+3]<<24}function i(e,n,t,r,u,i){var c=b[u],l=b[u+1],p=b[i],y=b[i+1];o(f,e,n),a(f,e,c,l);var d=f[r]^f[e],s=f[r+1]^f[e+1];f[r]=s,f[r+1]=d,o(f,t,r),d=f[n]^f[t],s=f[n+1]^f[t+1],f[n]=d>>>24^s<<8,f[n+1]=s>>>24^d<<8,o(f,e,n),a(f,e,p,y),d=f[r]^f[e],s=f[r+1]^f[e+1],f[r]=d>>>16^s<<16,f[r+1]=s>>>16^d<<16,o(f,t,r),d=f[n]^f[t],s=f[n+1]^f[t+1],f[n]=s>>>31^d<<1,f[n+1]=d>>>31^s<<1}var c=new Uint32Array([4089235720,1779033703,2227873595,3144134277,4271175723,1013904242,1595750129,2773480762,2917565137,1359893119,725511199,2600822924,4215389547,528734635,327033209,1541459225]),l=new Uint8Array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3,11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4,7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8,9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13,2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9,12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11,13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10,6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5,10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3].map(function(e){return 2*e})),f=new Uint32Array(32),b=new Uint32Array(32);function p(e,n){var t=0;for(t=0;t<16;t++)f[t]=e.h[t],f[t+16]=c[t];for(f[24]=f[24]^e.t,f[25]=f[25]^e.t/4294967296,n&&(f[28]=~f[28],f[29]=~f[29]),t=0;t<32;t++)b[t]=u(e.b,4*t);for(t=0;t<12;t++)i(0,8,16,24,l[16*t+0],l[16*t+1]),i(2,10,18,26,l[16*t+2],l[16*t+3]),i(4,12,20,28,l[16*t+4],l[16*t+5]),i(6,14,22,30,l[16*t+6],l[16*t+7]),i(0,10,20,30,l[16*t+8],l[16*t+9]),i(2,12,22,24,l[16*t+10],l[16*t+11]),i(4,14,16,26,l[16*t+12],l[16*t+13]),i(6,8,18,28,l[16*t+14],l[16*t+15]);for(t=0;t<16;t++)e.h[t]=e.h[t]^f[t]^f[t+16]}function y(e,n){if(0===e||e>64)throw new Error("Illegal output length, expected 0 < length <= 64");if(n&&n.length>64)throw new Error("Illegal key, expected Uint8Array with 0 < length <= 64");for(var t={b:new Uint8Array(128),h:new Uint32Array(16),t:0,c:0,outlen:e},r=0;r<16;r++)t.h[r]=c[r];var o=n?n.length:0;return t.h[0]^=16842752^o<<8^e,n&&(d(t,n),t.c=128),t}function d(e,n){for(var t=0;t>2]>>8*(3&t);return n}function v(e,n,t){t=t||64,e=r.normalizeInput(e);var o=y(t,n);return d(o,e),s(o)}e.exports={blake2b:v,blake2bHex:function(e,n,t){var o=v(e,n,t);return r.toHex(o)},blake2bInit:y,blake2bUpdate:d,blake2bFinal:s}},function(e,t){e.exports=n},function(e,n,t){"use strict";t.r(n);var r=t(0),o=t.n(r);const a=o.a.box.publicKeyLength+o.a.box.overheadLength;var u=t(1),i=t.n(u);function c(e,n){var t=i.a.blake2bInit(o.a.box.nonceLength,null);return i.a.blake2bUpdate(t,e),i.a.blake2bUpdate(t,n),i.a.blake2bFinal(t)}function l(e,n){var t=new Uint8Array(a+e.length),r=o.a.box.keyPair();t.set(r.publicKey);var u=c(r.publicKey,n),i=o.a.box(e,u,n,r.secretKey);return t.set(i,r.publicKey.length),function(e){for(var n=0;n Date: Mon, 1 Jun 2026 16:44:20 +0300 Subject: [PATCH 3/3] docs: update tutorial to run every 8 hours --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61d9183..992792e 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,7 @@ You can fully automate your LeetCode backup to a separate GitHub repository usin name: Daily LeetCode Sync on: schedule: - - cron: "0 0 * * *" + - cron: "0 */8 * * *" workflow_dispatch: jobs: