kalvium-worklog 1.4.1 → 1.4.3

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,9 @@ 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
+ // Start local HTTP server
65
65
  const tokenPromise = new Promise((resolve) => {
66
66
  const server = createServer((req, res) => {
67
- // Handle CORS + token capture
68
67
  res.setHeader("Access-Control-Allow-Origin", "*");
69
68
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
70
69
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -78,15 +77,14 @@ async function captureTokenViaBrowser() {
78
77
  body += chunk;
79
78
  });
80
79
  req.on("end", () => {
80
+ // Token capture endpoint
81
81
  if (req.url?.startsWith("/capture")) {
82
82
  try {
83
- // Try parsing as JSON first (POST body)
84
83
  let data;
85
84
  if (body) {
86
85
  data = JSON.parse(body);
87
86
  }
88
87
  else {
89
- // Try query param
90
88
  const url = new URL(req.url, `http://localhost:${PORT}`);
91
89
  const tokenParam = url.searchParams.get("token");
92
90
  if (!tokenParam) {
@@ -98,69 +96,125 @@ async function captureTokenViaBrowser() {
98
96
  }
99
97
  if (data.refresh_token) {
100
98
  res.writeHead(200, { "Content-Type": "text/html" });
101
- res.end("<html><body><h2>Token captured! You can close this tab.</h2></body></html>");
99
+ 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
100
  resolve(data);
103
101
  }
104
102
  else {
105
- res.writeHead(400);
106
- res.end("Invalid token — missing refresh_token");
103
+ res.writeHead(400, { "Content-Type": "text/html" });
104
+ res.end("<html><body><h2>Invalid token — missing refresh_token</h2></body></html>");
107
105
  resolve(null);
108
106
  }
109
107
  }
110
108
  catch {
111
- res.writeHead(400);
112
- res.end("Invalid JSON");
109
+ res.writeHead(400, { "Content-Type": "text/html" });
110
+ res.end("<html><body><h2>Invalid JSON</h2></body></html>");
113
111
  resolve(null);
114
112
  }
113
+ return;
115
114
  }
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
- }
115
+ // Main page — serves instructions + manual paste form
116
+ res.writeHead(200, { "Content-Type": "text/html" });
117
+ res.end(`<!DOCTYPE html>
118
+ <html>
119
+ <head>
120
+ <meta name="viewport" content="width=device-width, initial-scale=1">
121
+ <title>Kalvium Worklog Login</title>
122
+ <style>
123
+ * { box-sizing: border-box; }
124
+ body { font-family: -apple-system, sans-serif; max-width: 600px; margin: 0 auto; padding: 16px; line-height: 1.6; color: #333; }
125
+ h2 { color: #1a73e8; }
126
+ .step { background: #f0f4ff; border-radius: 12px; padding: 16px; margin: 12px 0; }
127
+ .step h3 { margin-top: 0; color: #1a73e8; }
128
+ .btn { display: block; text-align: center; background: #4285f4; color: white; padding: 14px; border-radius: 8px; text-decoration: none; font-size: 18px; font-weight: bold; margin: 12px 0; }
129
+ .btn-green { background: #34a853; }
130
+ .btn:active { opacity: 0.8; }
131
+ .code-box { background: #1e1e1e; color: #0f0; padding: 12px; border-radius: 8px; font-family: monospace; font-size: 12px; word-break: break-all; white-space: pre-wrap; user-select: all; }
132
+ .note { background: #fff8e1; border-radius: 8px; padding: 12px; margin: 12px 0; font-size: 14px; }
133
+ .warn { background: #fce4ec; border-radius: 8px; padding: 12px; margin: 12px 0; font-size: 14px; }
134
+ textarea { width: 100%; height: 120px; font-family: monospace; font-size: 12px; border: 2px solid #4285f4; border-radius: 8px; padding: 8px; }
135
+ #result { font-weight: bold; padding: 12px; border-radius: 8px; margin: 8px 0; display: none; }
136
+ .success { background: #e8f5e9; color: #2e7d32; }
137
+ .error { background: #ffebee; color: #c62828; }
138
+ </style>
139
+ </head>
140
+ <body>
141
+ <h2>Kalvium Worklog — Login</h2>
142
+
143
+ <div class="step">
144
+ <h3>Step 1: Log in to Kalvium</h3>
145
+ <p>Tap below, log in with Google (2FA if asked).</p>
146
+ <a class="btn btn-green" href="https://kalvium.community/internships" target="_blank">Open Kalvium →</a>
147
+ </div>
148
+
149
+ <div class="step">
150
+ <h3>Step 2: Extract token</h3>
151
+ <p>After logging in, go to the Kalvium tab.<br>
152
+ <b>Type</b> this in the address bar (don't paste — type <code>javascript:</code> yourself, then paste the rest):</p>
153
+ <div class="code-box" id="jscode">javascript:void(function(){var t;for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i),v=localStorage.getItem(i);if(v&&v.includes('refresh_token')){t=v}}if(!t){for(var i=0;i<sessionStorage.length;i++){var k=sessionStorage.key(i),v=sessionStorage.getItem(i);if(v&&v.includes('refresh_token')){t=v}}}if(t){fetch('http://localhost:${PORT}/capture',{method:'POST',body:t}).then(function(r){alert(r.ok?'Token sent! Go back to Termux':'Failed: '+r.status)}).catch(function(e){alert('Error: '+e)})}else{alert('No token found. Are you logged in?')}})()</div>
154
+ <p><small>👆 Long-press the code above → "Copy", then go to Kalvium tab, type <code>javascript:</code> in address bar, paste the rest after it, press Enter.</small></p>
155
+ </div>
156
+
157
+ <div class="warn">
158
+ <b>Brave users:</b> Brave strips <code>javascript:</code> when pasting. You must <b>type</b> <code>javascript:</code> manually, then paste only the code after <code>javascript:</code>.
159
+ </div>
160
+
161
+ <div class="step">
162
+ <h3>Or: Paste token manually</h3>
163
+ <p>If the above doesn't work, extract the token another way and paste it here:</p>
164
+ <textarea id="manualToken" placeholder='Paste token JSON here (starts with {"access_token"...'></textarea>
165
+ <button class="btn" onclick="sendManual()">Send Token</button>
166
+ <div id="result"></div>
167
+ </div>
168
+
169
+ <script>
170
+ function sendManual() {
171
+ var val = document.getElementById('manualToken').value.trim();
172
+ var result = document.getElementById('result');
173
+ result.style.display = 'block';
174
+ if (!val) { result.className = 'error'; result.textContent = 'Paste token JSON first'; return; }
175
+ fetch('http://localhost:${PORT}/capture', { method: 'POST', body: val })
176
+ .then(function(r) {
177
+ if (r.ok) { result.className = 'success'; result.textContent = '✓ Token sent! Go back to Termux.'; }
178
+ else { result.className = 'error'; result.textContent = 'Failed: ' + r.status; }
179
+ })
180
+ .catch(function(e) { result.className = 'error'; result.textContent = 'Error: ' + e; });
181
+ }
182
+ </script>
183
+
184
+ </body>
185
+ </html>`);
126
186
  });
127
187
  });
128
188
  server.listen(PORT, () => {
129
189
  console.log(` Local server running on http://localhost:${PORT}`);
130
190
  });
131
- // Timeout after 5 minutes
132
191
  setTimeout(() => {
133
192
  server.close();
134
193
  resolve(null);
135
194
  }, 300000);
136
195
  });
137
- // Open kalvium.community in the phone's default browser
138
- const url = "https://kalvium.community/internships";
196
+ // Open the localhost page in the browser
197
+ const localUrl = `http://localhost:${PORT}`;
139
198
  try {
140
199
  if (process.platform === "android") {
141
- // Termux: use termux-open-url
142
- execSync(`termux-open-url ${url}`, { stdio: "ignore" });
200
+ execSync(`termux-open-url ${localUrl}`, { stdio: "ignore" });
143
201
  }
144
202
  else {
145
- // Other platforms: try xdg-open or open
146
- execSync(`xdg-open ${url} || open ${url}`, { stdio: "ignore" });
203
+ execSync(`xdg-open ${localUrl} || open ${localUrl}`, {
204
+ stdio: "ignore",
205
+ });
147
206
  }
148
- console.log(` Opened ${url} in your browser.`);
207
+ console.log(` Opened ${localUrl} in your browser.`);
149
208
  }
150
209
  catch {
151
- console.log(` Could not auto-open browser. Please open: ${url}`);
210
+ console.log(` Could not auto-open browser. Please open: ${localUrl}`);
152
211
  }
153
212
  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.)");
213
+ console.log(" A page opened in your browser with instructions:");
214
+ console.log(" 1. Click 'Open Kalvium' and log in");
215
+ console.log(" 2. Long-press 'Capture Token' → Bookmark it");
216
+ console.log(" 3. Go to Kalvium tab open the bookmark");
217
+ console.log(" ────────────────────────────────────────────");
164
218
  console.log("\n Waiting for token (up to 5 minutes)...\n");
165
219
  const data = await tokenPromise;
166
220
  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.3",
4
4
  "description": "Auto-submit your daily Kalvium worklog without opening the website",
5
5
  "keywords": [
6
6
  "kalvium",