kalvium-worklog 1.4.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,10 +61,11 @@ async function captureTokenViaBrowser() {
61
61
  console.log("\n ========================================");
62
62
  console.log(" Browser-based token capture (no Playwright)");
63
63
  console.log(" ========================================\n");
64
- // Start local HTTP server to receive the token
64
+ // The JS that runs on kalvium.community to extract and send the token
65
+ const bookmarkletJS = `javascript:void(function(){var t=localStorage.getItem('kc-token')||localStorage.getItem('keycloak-token');if(!t){for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i),v=localStorage.getItem(k);if(v&&v.includes('refresh_token')){t=v;break}}}if(!t){for(var i=0;i<sessionStorage.length;i++){var k=sessionStorage.key(i),v=sessionStorage.getItem(k);if(v&&v.includes('refresh_token')){t=v;break}}}if(t){fetch('http://localhost:${PORT}/capture',{method:'POST',headers:{'Content-Type':'text/plain'},body:t}).then(function(r){if(r.ok)alert('Token sent! You can close this tab.');else alert('Failed: '+r.status)}).catch(function(e){alert('Error: '+e)})}else{alert('No token found in storage. Make sure you are logged in.')}})()`;
66
+ // Start local HTTP server
65
67
  const tokenPromise = new Promise((resolve) => {
66
68
  const server = createServer((req, res) => {
67
- // Handle CORS + token capture
68
69
  res.setHeader("Access-Control-Allow-Origin", "*");
69
70
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
70
71
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -78,15 +79,14 @@ async function captureTokenViaBrowser() {
78
79
  body += chunk;
79
80
  });
80
81
  req.on("end", () => {
82
+ // Token capture endpoint
81
83
  if (req.url?.startsWith("/capture")) {
82
84
  try {
83
- // Try parsing as JSON first (POST body)
84
85
  let data;
85
86
  if (body) {
86
87
  data = JSON.parse(body);
87
88
  }
88
89
  else {
89
- // Try query param
90
90
  const url = new URL(req.url, `http://localhost:${PORT}`);
91
91
  const tokenParam = url.searchParams.get("token");
92
92
  if (!tokenParam) {
@@ -98,69 +98,103 @@ async function captureTokenViaBrowser() {
98
98
  }
99
99
  if (data.refresh_token) {
100
100
  res.writeHead(200, { "Content-Type": "text/html" });
101
- res.end("<html><body><h2>Token captured! You can close this tab.</h2></body></html>");
101
+ res.end("<html><body style='font-family:sans-serif;text-align:center;padding:40px'><h2>✓ Token captured!</h2><p>You can close this tab and go back to Termux.</p></body></html>");
102
102
  resolve(data);
103
103
  }
104
104
  else {
105
- res.writeHead(400);
106
- res.end("Invalid token — missing refresh_token");
105
+ res.writeHead(400, { "Content-Type": "text/html" });
106
+ res.end("<html><body><h2>Invalid token — missing refresh_token</h2></body></html>");
107
107
  resolve(null);
108
108
  }
109
109
  }
110
110
  catch {
111
- res.writeHead(400);
112
- res.end("Invalid JSON");
111
+ res.writeHead(400, { "Content-Type": "text/html" });
112
+ res.end("<html><body><h2>Invalid JSON</h2></body></html>");
113
113
  resolve(null);
114
114
  }
115
+ return;
115
116
  }
116
- else {
117
- res.writeHead(200, { "Content-Type": "text/html" });
118
- res.end(`
119
- <html><body>
120
- <h2>Kalvium Worklog — Token Capture</h2>
121
- <p>If you're seeing this, the local server is running.</p>
122
- <p>Go back to the Kalvium tab and paste the JavaScript snippet.</p>
123
- </body></html>
124
- `);
125
- }
117
+ // Main page — serves the bookmarklet + instructions
118
+ res.writeHead(200, { "Content-Type": "text/html" });
119
+ res.end(`<!DOCTYPE html>
120
+ <html>
121
+ <head>
122
+ <meta name="viewport" content="width=device-width, initial-scale=1">
123
+ <title>Kalvium Worklog Token Capture</title>
124
+ <style>
125
+ body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; line-height: 1.6; }
126
+ .step { background: #f0f4ff; border-radius: 12px; padding: 16px; margin: 12px 0; }
127
+ .step h3 { margin-top: 0; }
128
+ .bookmarklet { display: inline-block; background: #4285f4; color: white; padding: 14px 24px; border-radius: 8px; text-decoration: none; font-size: 18px; font-weight: bold; margin: 12px 0; }
129
+ .bookmarklet:active { background: #3367d6; }
130
+ .note { background: #fff8e1; border-radius: 8px; padding: 12px; margin: 12px 0; font-size: 14px; }
131
+ code { background: #f5f5f5; padding: 2px 6px; border-radius: 4px; font-size: 13px; word-break: break-all; }
132
+ .kalvium-link { display: inline-block; background: #34a853; color: white; padding: 12px 20px; border-radius: 8px; text-decoration: none; font-size: 16px; margin: 8px 0; }
133
+ </style>
134
+ </head>
135
+ <body>
136
+ <h2>Kalvium Worklog — Token Capture</h2>
137
+
138
+ <div class="step">
139
+ <h3>Step 1: Open Kalvium & log in</h3>
140
+ <p>Tap the button below to open Kalvium. Log in with Google (complete 2FA if asked).</p>
141
+ <a class="kalvium-link" href="https://kalvium.community/internships" target="_blank">Open Kalvium →</a>
142
+ </div>
143
+
144
+ <div class="step">
145
+ <h3>Step 2: Save this bookmarklet</h3>
146
+ <p><b>Long-press</b> the blue button below, then select <b>"Bookmark link"</b> or <b>"Add bookmark"</b>.</p>
147
+ <a class="bookmarklet" href="${bookmarkletJS.replace(/"/g, "&quot;")}">📋 Capture Token</a>
148
+ <p><small>If long-press doesn't work: bookmark this page, then edit the bookmark and change the URL to the code below.</small></p>
149
+ </div>
150
+
151
+ <div class="step">
152
+ <h3>Step 3: Run the bookmarklet</h3>
153
+ <p>Go back to the <b>Kalvium tab</b> (where you logged in).<br>
154
+ Open your <b>bookmarks menu</b> and tap <b>"📋 Capture Token"</b>.</p>
155
+ <p>You should see <b>"Token sent!"</b> — then come back to Termux.</p>
156
+ </div>
157
+
158
+ <div class="note">
159
+ <b>Trouble with bookmarklet?</b> Copy this code, open Kalvium, then paste it in the address bar (type <code>javascript:</code> first, then paste the rest after the colon):
160
+ <br><br>
161
+ <code>${bookmarkletJS.replace(/^javascript:/, "")}</code>
162
+ </div>
163
+
164
+ </body>
165
+ </html>`);
126
166
  });
127
167
  });
128
168
  server.listen(PORT, () => {
129
169
  console.log(` Local server running on http://localhost:${PORT}`);
130
170
  });
131
- // Timeout after 5 minutes
132
171
  setTimeout(() => {
133
172
  server.close();
134
173
  resolve(null);
135
174
  }, 300000);
136
175
  });
137
- // Open kalvium.community in the phone's default browser
138
- const url = "https://kalvium.community/internships";
176
+ // Open the localhost page in the browser
177
+ const localUrl = `http://localhost:${PORT}`;
139
178
  try {
140
179
  if (process.platform === "android") {
141
- // Termux: use termux-open-url
142
- execSync(`termux-open-url ${url}`, { stdio: "ignore" });
180
+ execSync(`termux-open-url ${localUrl}`, { stdio: "ignore" });
143
181
  }
144
182
  else {
145
- // Other platforms: try xdg-open or open
146
- execSync(`xdg-open ${url} || open ${url}`, { stdio: "ignore" });
183
+ execSync(`xdg-open ${localUrl} || open ${localUrl}`, {
184
+ stdio: "ignore",
185
+ });
147
186
  }
148
- console.log(` Opened ${url} in your browser.`);
187
+ console.log(` Opened ${localUrl} in your browser.`);
149
188
  }
150
189
  catch {
151
- console.log(` Could not auto-open browser. Please open: ${url}`);
190
+ console.log(` Could not auto-open browser. Please open: ${localUrl}`);
152
191
  }
153
192
  console.log("\n ────────────────────────────────────────────");
154
- console.log(" 1. Log in with Google (complete 2FA if needed)");
155
- console.log(" 2. After you're logged in, copy this line:");
156
- console.log(" ────────────────────────────────────────────\n");
157
- // The JS snippet extracts tokens from the page's network requests
158
- // and sends them to our local server
159
- const jsSnippet = `javascript:void(function(){var t=localStorage.getItem('kc-token')||localStorage.getItem('keycloak-token');if(!t){for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i),v=localStorage.getItem(k);if(v&&v.includes('refresh_token')){t=v;break}}}if(!t){for(var i=0;i<sessionStorage.length;i++){var k=sessionStorage.key(i),v=sessionStorage.getItem(k);if(v&&v.includes('refresh_token')){t=v;break}}}if(t){fetch('http://localhost:${PORT}/capture',{method:'POST',headers:{'Content-Type':'text/plain'},body:t}).then(function(r){if(r.ok)alert('Token sent! You can close this tab.');else alert('Failed: '+r.status)}).catch(function(e){alert('Error: '+e)})}else{alert('No token found in storage. Make sure you are logged in.')}})()`;
160
- console.log(` ${jsSnippet}\n`);
161
- console.log(" 3. Paste it in the browser ADDRESS BAR (where you type URLs)");
162
- console.log(" and press Enter. (Remove any leading 'javascript:' that");
163
- console.log(" the browser strips, then type it manually if needed.)");
193
+ console.log(" A page opened in your browser with instructions:");
194
+ console.log(" 1. Click 'Open Kalvium' and log in");
195
+ console.log(" 2. Long-press 'Capture Token' → Bookmark it");
196
+ console.log(" 3. Go to Kalvium tab open the bookmark");
197
+ console.log(" ────────────────────────────────────────────");
164
198
  console.log("\n Waiting for token (up to 5 minutes)...\n");
165
199
  const data = await tokenPromise;
166
200
  if (data) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kalvium-worklog",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Auto-submit your daily Kalvium worklog without opening the website",
5
5
  "keywords": [
6
6
  "kalvium",