@marcfargas/go-easy 0.0.1 → 0.3.0
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.
- package/CHANGELOG.md +90 -0
- package/LICENSE +21 -0
- package/README.md +224 -0
- package/dist/auth-flow.d.ts +50 -0
- package/dist/auth-flow.d.ts.map +1 -0
- package/dist/auth-flow.js +219 -0
- package/dist/auth-flow.js.map +1 -0
- package/dist/auth-server.d.ts +18 -0
- package/dist/auth-server.d.ts.map +1 -0
- package/dist/auth-server.js +327 -0
- package/dist/auth-server.js.map +1 -0
- package/dist/auth-store.d.ts +81 -0
- package/dist/auth-store.d.ts.map +1 -0
- package/dist/auth-store.js +185 -0
- package/dist/auth-store.js.map +1 -0
- package/dist/auth.d.ts +47 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +131 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin/calendar.d.ts +17 -0
- package/dist/bin/calendar.d.ts.map +1 -0
- package/dist/bin/calendar.js +224 -0
- package/dist/bin/calendar.js.map +1 -0
- package/dist/bin/drive.d.ts +18 -0
- package/dist/bin/drive.d.ts.map +1 -0
- package/dist/bin/drive.js +205 -0
- package/dist/bin/drive.js.map +1 -0
- package/dist/bin/easy.d.ts +11 -0
- package/dist/bin/easy.d.ts.map +1 -0
- package/dist/bin/easy.js +140 -0
- package/dist/bin/easy.js.map +1 -0
- package/dist/bin/gmail.d.ts +25 -0
- package/dist/bin/gmail.d.ts.map +1 -0
- package/dist/bin/gmail.js +243 -0
- package/dist/bin/gmail.js.map +1 -0
- package/dist/bin/tasks.d.ts +17 -0
- package/dist/bin/tasks.d.ts.map +1 -0
- package/dist/bin/tasks.js +190 -0
- package/dist/bin/tasks.js.map +1 -0
- package/dist/calendar/helpers.d.ts +35 -0
- package/dist/calendar/helpers.d.ts.map +1 -0
- package/dist/calendar/helpers.js +178 -0
- package/dist/calendar/helpers.js.map +1 -0
- package/dist/calendar/index.d.ts +64 -0
- package/dist/calendar/index.d.ts.map +1 -0
- package/dist/calendar/index.js +210 -0
- package/dist/calendar/index.js.map +1 -0
- package/dist/calendar/types.d.ts +191 -0
- package/dist/calendar/types.d.ts.map +1 -0
- package/dist/calendar/types.js +12 -0
- package/dist/calendar/types.js.map +1 -0
- package/dist/drive/helpers.d.ts +22 -0
- package/dist/drive/helpers.d.ts.map +1 -0
- package/dist/drive/helpers.js +85 -0
- package/dist/drive/helpers.js.map +1 -0
- package/dist/drive/index.d.ts +114 -0
- package/dist/drive/index.d.ts.map +1 -0
- package/dist/drive/index.js +418 -0
- package/dist/drive/index.js.map +1 -0
- package/dist/drive/types.d.ts +91 -0
- package/dist/drive/types.d.ts.map +1 -0
- package/dist/drive/types.js +5 -0
- package/dist/drive/types.js.map +1 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +73 -0
- package/dist/errors.js.map +1 -0
- package/dist/gmail/helpers.d.ts +59 -0
- package/dist/gmail/helpers.d.ts.map +1 -0
- package/dist/gmail/helpers.js +308 -0
- package/dist/gmail/helpers.js.map +1 -0
- package/dist/gmail/index.d.ts +95 -0
- package/dist/gmail/index.d.ts.map +1 -0
- package/dist/gmail/index.js +465 -0
- package/dist/gmail/index.js.map +1 -0
- package/dist/gmail/markdown.d.ts +22 -0
- package/dist/gmail/markdown.d.ts.map +1 -0
- package/dist/gmail/markdown.js +30 -0
- package/dist/gmail/markdown.js.map +1 -0
- package/dist/gmail/types.d.ts +154 -0
- package/dist/gmail/types.d.ts.map +1 -0
- package/dist/gmail/types.js +5 -0
- package/dist/gmail/types.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/safety.d.ts +58 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +61 -0
- package/dist/safety.js.map +1 -0
- package/dist/scopes.d.ts +16 -0
- package/dist/scopes.d.ts.map +1 -0
- package/dist/scopes.js +28 -0
- package/dist/scopes.js.map +1 -0
- package/dist/tasks/helpers.d.ts +10 -0
- package/dist/tasks/helpers.d.ts.map +1 -0
- package/dist/tasks/helpers.js +33 -0
- package/dist/tasks/helpers.js.map +1 -0
- package/dist/tasks/index.d.ts +63 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +253 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/types.d.ts +79 -0
- package/dist/tasks/types.d.ts.map +1 -0
- package/dist/tasks/types.js +5 -0
- package/dist/tasks/types.js.map +1 -0
- package/package.json +73 -4
- package/skills/go-easy/SKILL.md +146 -0
- package/skills/go-easy/calendar.md +366 -0
- package/skills/go-easy/drive.md +309 -0
- package/skills/go-easy/gmail.md +478 -0
- package/skills/go-easy/tasks.md +260 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* auth-server — Background loopback OAuth callback server.
|
|
4
|
+
*
|
|
5
|
+
* Spawned as a detached child by auth-flow.ts.
|
|
6
|
+
* Listens on 127.0.0.1:<port>, waits for Google OAuth callback,
|
|
7
|
+
* exchanges code for token, writes result to pending/<email>.json,
|
|
8
|
+
* updates accounts.json.
|
|
9
|
+
*
|
|
10
|
+
* Communicates with parent via:
|
|
11
|
+
* 1. stdout: JSON line with { port, pid, authUrl } (parent reads this, then detaches)
|
|
12
|
+
* 2. pending/<email>.json file (poll target for subsequent CLI calls)
|
|
13
|
+
*
|
|
14
|
+
* Usage (not meant to be called directly):
|
|
15
|
+
* node auth-server.js <email> <port>
|
|
16
|
+
*/
|
|
17
|
+
import { createServer } from 'node:http';
|
|
18
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
21
|
+
import { URL } from 'node:url';
|
|
22
|
+
// ─── Constants ─────────────────────────────────────────────
|
|
23
|
+
const TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes (D6)
|
|
24
|
+
const GO_EASY_DIR = join(homedir(), '.go-easy');
|
|
25
|
+
const PENDING_DIR = join(GO_EASY_DIR, 'pending');
|
|
26
|
+
const CREDENTIALS_FILE = join(GO_EASY_DIR, 'credentials.json');
|
|
27
|
+
const ACCOUNTS_FILE = join(GO_EASY_DIR, 'accounts.json');
|
|
28
|
+
// All scopes requested by default (D2)
|
|
29
|
+
const ALL_SCOPES = [
|
|
30
|
+
'https://mail.google.com/',
|
|
31
|
+
'https://www.googleapis.com/auth/drive',
|
|
32
|
+
'https://www.googleapis.com/auth/calendar',
|
|
33
|
+
'https://www.googleapis.com/auth/tasks',
|
|
34
|
+
];
|
|
35
|
+
// ─── Args ──────────────────────────────────────────────────
|
|
36
|
+
const email = process.argv[2];
|
|
37
|
+
const requestedPort = parseInt(process.argv[3] || '0', 10);
|
|
38
|
+
if (!email) {
|
|
39
|
+
process.stderr.write('Usage: auth-server <email> [port]\n');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
// ─── HTML responses ────────────────────────────────────────
|
|
43
|
+
const SUCCESS_HTML = `<!DOCTYPE html>
|
|
44
|
+
<html>
|
|
45
|
+
<head><meta charset="utf-8"></head>
|
|
46
|
+
<body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#f0fdf4;">
|
|
47
|
+
<div style="text-align:center;max-width:400px;">
|
|
48
|
+
<h1 style="color:#16a34a;">✅ Authorization successful!</h1>
|
|
49
|
+
<p>You can close this tab and return to your AI assistant.</p>
|
|
50
|
+
</div>
|
|
51
|
+
</body>
|
|
52
|
+
</html>`;
|
|
53
|
+
const DENIED_HTML = `<!DOCTYPE html>
|
|
54
|
+
<html>
|
|
55
|
+
<head><meta charset="utf-8"></head>
|
|
56
|
+
<body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#fef2f2;">
|
|
57
|
+
<div style="text-align:center;max-width:400px;">
|
|
58
|
+
<h1 style="color:#dc2626;">❌ Authorization declined</h1>
|
|
59
|
+
<p>You can close this tab. Run <code>npx go-easy auth add ${email}</code> to try again.</p>
|
|
60
|
+
</div>
|
|
61
|
+
</body>
|
|
62
|
+
</html>`;
|
|
63
|
+
const PARTIAL_HTML = (granted, missing) => `<!DOCTYPE html>
|
|
64
|
+
<html>
|
|
65
|
+
<head><meta charset="utf-8"></head>
|
|
66
|
+
<body style="font-family:system-ui;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#fffbeb;">
|
|
67
|
+
<div style="text-align:center;max-width:500px;">
|
|
68
|
+
<h1 style="color:#d97706;">⚠️ Partial authorization</h1>
|
|
69
|
+
<p>Some permissions were not granted. Granted: <strong>${granted.join(', ')}</strong></p>
|
|
70
|
+
<p>Missing: <strong>${missing.join(', ')}</strong></p>
|
|
71
|
+
<p>Run <code>npx go-easy auth add ${email}</code> to add missing permissions.</p>
|
|
72
|
+
</div>
|
|
73
|
+
</body>
|
|
74
|
+
</html>`;
|
|
75
|
+
// ─── Helpers ───────────────────────────────────────────────
|
|
76
|
+
function pendingFile() {
|
|
77
|
+
return join(PENDING_DIR, `${email.toLowerCase()}.json`);
|
|
78
|
+
}
|
|
79
|
+
async function writePending(data) {
|
|
80
|
+
await mkdir(PENDING_DIR, { recursive: true });
|
|
81
|
+
await writeFile(pendingFile(), JSON.stringify(data, null, 2), 'utf-8');
|
|
82
|
+
}
|
|
83
|
+
async function readCredentials() {
|
|
84
|
+
const raw = await readFile(CREDENTIALS_FILE, 'utf-8');
|
|
85
|
+
return JSON.parse(raw);
|
|
86
|
+
}
|
|
87
|
+
function scopeToService(scope) {
|
|
88
|
+
if (scope === 'https://mail.google.com/')
|
|
89
|
+
return 'gmail';
|
|
90
|
+
if (scope === 'https://www.googleapis.com/auth/drive')
|
|
91
|
+
return 'drive';
|
|
92
|
+
if (scope === 'https://www.googleapis.com/auth/calendar')
|
|
93
|
+
return 'calendar';
|
|
94
|
+
if (scope === 'https://www.googleapis.com/auth/tasks')
|
|
95
|
+
return 'tasks';
|
|
96
|
+
return scope;
|
|
97
|
+
}
|
|
98
|
+
// ─── Token exchange ────────────────────────────────────────
|
|
99
|
+
async function exchangeCodeForToken(code, redirectUri, clientId, clientSecret) {
|
|
100
|
+
const params = new URLSearchParams({
|
|
101
|
+
code,
|
|
102
|
+
client_id: clientId,
|
|
103
|
+
client_secret: clientSecret,
|
|
104
|
+
redirect_uri: redirectUri,
|
|
105
|
+
grant_type: 'authorization_code',
|
|
106
|
+
});
|
|
107
|
+
const res = await fetch('https://oauth2.googleapis.com/token', {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
110
|
+
body: params.toString(),
|
|
111
|
+
});
|
|
112
|
+
if (!res.ok) {
|
|
113
|
+
const body = await res.text();
|
|
114
|
+
throw new Error(`Token exchange failed (${res.status}): ${body}`);
|
|
115
|
+
}
|
|
116
|
+
return res.json();
|
|
117
|
+
}
|
|
118
|
+
// ─── Account store update ──────────────────────────────────
|
|
119
|
+
async function updateAccountStore(refreshToken, grantedScopes) {
|
|
120
|
+
// Read existing store (or create new)
|
|
121
|
+
let store;
|
|
122
|
+
try {
|
|
123
|
+
const raw = await readFile(ACCOUNTS_FILE, 'utf-8');
|
|
124
|
+
store = JSON.parse(raw);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
store = { version: 1, accounts: [] };
|
|
128
|
+
}
|
|
129
|
+
const normalizedEmail = email.toLowerCase().trim();
|
|
130
|
+
const now = new Date().toISOString();
|
|
131
|
+
// Find or create account
|
|
132
|
+
let account = store.accounts.find((a) => a.email.toLowerCase() === normalizedEmail);
|
|
133
|
+
if (!account) {
|
|
134
|
+
account = {
|
|
135
|
+
email: normalizedEmail,
|
|
136
|
+
tokens: {},
|
|
137
|
+
addedAt: now,
|
|
138
|
+
};
|
|
139
|
+
store.accounts.push(account);
|
|
140
|
+
}
|
|
141
|
+
const tokens = (account.tokens ?? {});
|
|
142
|
+
// Write combined token
|
|
143
|
+
tokens.combined = {
|
|
144
|
+
refreshToken,
|
|
145
|
+
scopes: grantedScopes,
|
|
146
|
+
grantedAt: now,
|
|
147
|
+
};
|
|
148
|
+
// D1: Delete per-service tokens after successful upgrade
|
|
149
|
+
// (only if combined has all scopes those per-service tokens had)
|
|
150
|
+
for (const svc of ['gmail', 'drive', 'calendar']) {
|
|
151
|
+
const svcToken = tokens[svc];
|
|
152
|
+
if (svcToken?.scopes) {
|
|
153
|
+
const covered = svcToken.scopes.every((s) => grantedScopes.includes(s));
|
|
154
|
+
if (covered) {
|
|
155
|
+
delete tokens[svc];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
account.tokens = tokens;
|
|
160
|
+
// Atomic write
|
|
161
|
+
const tmpFile = ACCOUNTS_FILE + '.tmp';
|
|
162
|
+
await writeFile(tmpFile, JSON.stringify(store, null, 2), 'utf-8');
|
|
163
|
+
const { rename } = await import('node:fs/promises');
|
|
164
|
+
await rename(tmpFile, ACCOUNTS_FILE);
|
|
165
|
+
}
|
|
166
|
+
// ─── HTTP Server ───────────────────────────────────────────
|
|
167
|
+
async function start() {
|
|
168
|
+
const creds = await readCredentials();
|
|
169
|
+
const server = createServer(async (req, res) => {
|
|
170
|
+
// Only handle the callback path
|
|
171
|
+
const url = new URL(req.url ?? '/', `http://127.0.0.1`);
|
|
172
|
+
if (url.pathname !== '/callback') {
|
|
173
|
+
res.writeHead(404);
|
|
174
|
+
res.end('Not found');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// Check for error (user denied)
|
|
178
|
+
const error = url.searchParams.get('error');
|
|
179
|
+
if (error) {
|
|
180
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
181
|
+
res.end(DENIED_HTML);
|
|
182
|
+
await writePending({
|
|
183
|
+
status: 'denied',
|
|
184
|
+
message: `User declined authorization: ${error}`,
|
|
185
|
+
completedAt: new Date().toISOString(),
|
|
186
|
+
});
|
|
187
|
+
shutdown();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Get the authorization code
|
|
191
|
+
const code = url.searchParams.get('code');
|
|
192
|
+
if (!code) {
|
|
193
|
+
res.writeHead(400);
|
|
194
|
+
res.end('Missing code parameter');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const redirectUri = `http://127.0.0.1:${server.address().port}/callback`;
|
|
199
|
+
// Exchange code for token
|
|
200
|
+
const tokenResponse = await exchangeCodeForToken(code, redirectUri, creds.clientId, creds.clientSecret);
|
|
201
|
+
if (!tokenResponse.refresh_token) {
|
|
202
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
203
|
+
res.end(`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body style="font-family:system-ui;text-align:center;padding:40px;">
|
|
204
|
+
<h1 style="color:#dc2626;">Error: No refresh token received</h1>
|
|
205
|
+
<p>Google did not return a refresh token. This can happen if the app was previously authorized.
|
|
206
|
+
Try revoking access at <a href="https://myaccount.google.com/permissions">Google Account Permissions</a>
|
|
207
|
+
and running <code>npx go-easy auth add ${email}</code> again.</p>
|
|
208
|
+
</body></html>`);
|
|
209
|
+
await writePending({
|
|
210
|
+
status: 'error',
|
|
211
|
+
message: 'No refresh token received — revoke at https://myaccount.google.com/permissions and retry',
|
|
212
|
+
completedAt: new Date().toISOString(),
|
|
213
|
+
});
|
|
214
|
+
shutdown();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// Parse granted scopes
|
|
218
|
+
const grantedScopeString = tokenResponse.scope || '';
|
|
219
|
+
const grantedScopes = grantedScopeString.split(' ').filter(Boolean);
|
|
220
|
+
// Check for partial scopes
|
|
221
|
+
const missingScopes = ALL_SCOPES.filter((s) => !grantedScopes.includes(s));
|
|
222
|
+
// Update account store
|
|
223
|
+
await updateAccountStore(tokenResponse.refresh_token, grantedScopes);
|
|
224
|
+
if (missingScopes.length === 0) {
|
|
225
|
+
// Full success
|
|
226
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
227
|
+
res.end(SUCCESS_HTML);
|
|
228
|
+
await writePending({
|
|
229
|
+
status: 'complete',
|
|
230
|
+
email,
|
|
231
|
+
scopes: grantedScopes.map(scopeToService),
|
|
232
|
+
completedAt: new Date().toISOString(),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// Partial authorization
|
|
237
|
+
const grantedNames = grantedScopes.map(scopeToService);
|
|
238
|
+
const missingNames = missingScopes.map(scopeToService);
|
|
239
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
240
|
+
res.end(PARTIAL_HTML(grantedNames, missingNames));
|
|
241
|
+
await writePending({
|
|
242
|
+
status: 'partial',
|
|
243
|
+
email,
|
|
244
|
+
grantedScopes: grantedNames,
|
|
245
|
+
missingScopes: missingNames,
|
|
246
|
+
message: `User did not grant all requested scopes`,
|
|
247
|
+
completedAt: new Date().toISOString(),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
shutdown();
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
254
|
+
res.writeHead(500);
|
|
255
|
+
res.end(`Error: ${msg}`);
|
|
256
|
+
await writePending({
|
|
257
|
+
status: 'error',
|
|
258
|
+
message: msg,
|
|
259
|
+
completedAt: new Date().toISOString(),
|
|
260
|
+
});
|
|
261
|
+
shutdown();
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
// Try to listen on requested port (0 = random)
|
|
265
|
+
await new Promise((resolve, reject) => {
|
|
266
|
+
server.on('error', reject);
|
|
267
|
+
server.listen(requestedPort, '127.0.0.1', () => resolve());
|
|
268
|
+
});
|
|
269
|
+
const addr = server.address();
|
|
270
|
+
const port = addr.port;
|
|
271
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
272
|
+
// Build Google OAuth URL
|
|
273
|
+
const authUrl = buildAuthUrl(creds.clientId, redirectUri);
|
|
274
|
+
// Write initial pending file
|
|
275
|
+
await writePending({
|
|
276
|
+
status: 'waiting',
|
|
277
|
+
port,
|
|
278
|
+
pid: process.pid,
|
|
279
|
+
authUrl,
|
|
280
|
+
startedAt: new Date().toISOString(),
|
|
281
|
+
expiresAt: new Date(Date.now() + TIMEOUT_MS).toISOString(),
|
|
282
|
+
});
|
|
283
|
+
// No stdout — parent polls the pending file instead
|
|
284
|
+
// (stdio is 'ignore' when spawned detached)
|
|
285
|
+
// Set timeout
|
|
286
|
+
const timer = setTimeout(() => {
|
|
287
|
+
writePending({
|
|
288
|
+
status: 'expired',
|
|
289
|
+
message: `Authorization not completed within ${TIMEOUT_MS / 1000 / 60} minutes`,
|
|
290
|
+
completedAt: new Date().toISOString(),
|
|
291
|
+
}).finally(() => {
|
|
292
|
+
shutdown();
|
|
293
|
+
});
|
|
294
|
+
}, TIMEOUT_MS);
|
|
295
|
+
function shutdown() {
|
|
296
|
+
clearTimeout(timer);
|
|
297
|
+
server.close(() => {
|
|
298
|
+
process.exit(0);
|
|
299
|
+
});
|
|
300
|
+
// Force exit after 3s if close hangs
|
|
301
|
+
setTimeout(() => process.exit(0), 3000).unref();
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function buildAuthUrl(clientId, redirectUri) {
|
|
305
|
+
const params = new URLSearchParams({
|
|
306
|
+
client_id: clientId,
|
|
307
|
+
redirect_uri: redirectUri,
|
|
308
|
+
response_type: 'code',
|
|
309
|
+
scope: ALL_SCOPES.join(' '),
|
|
310
|
+
access_type: 'offline',
|
|
311
|
+
prompt: 'consent', // Force consent to get refresh_token
|
|
312
|
+
login_hint: email,
|
|
313
|
+
});
|
|
314
|
+
return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
315
|
+
}
|
|
316
|
+
// ─── Go ────────────────────────────────────────────────────
|
|
317
|
+
start().catch((err) => {
|
|
318
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
319
|
+
process.stderr.write(`auth-server error: ${msg}\n`);
|
|
320
|
+
// Try to write error to pending file
|
|
321
|
+
writePending({
|
|
322
|
+
status: 'error',
|
|
323
|
+
message: msg,
|
|
324
|
+
completedAt: new Date().toISOString(),
|
|
325
|
+
}).finally(() => process.exit(1));
|
|
326
|
+
});
|
|
327
|
+
//# sourceMappingURL=auth-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-server.js","sourceRoot":"","sources":["../src/auth-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth store — manages the ~/.go-easy/ token store.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Read/write accounts.json (v1 schema, atomic writes)
|
|
6
|
+
* - File permissions (0o700 dir, 0o600 files)
|
|
7
|
+
* - Provide typed account/token resolution
|
|
8
|
+
*
|
|
9
|
+
* Does NOT handle OAuth flows — that's auth-flow.ts (Phase 2).
|
|
10
|
+
*/
|
|
11
|
+
export type GoogleService = 'gmail' | 'drive' | 'calendar' | 'tasks';
|
|
12
|
+
export interface OAuthToken {
|
|
13
|
+
refreshToken: string;
|
|
14
|
+
scopes: string[];
|
|
15
|
+
grantedAt: string;
|
|
16
|
+
}
|
|
17
|
+
export interface GoEasyAccount {
|
|
18
|
+
email: string;
|
|
19
|
+
tokens: {
|
|
20
|
+
combined?: OAuthToken;
|
|
21
|
+
gmail?: OAuthToken;
|
|
22
|
+
drive?: OAuthToken;
|
|
23
|
+
calendar?: OAuthToken;
|
|
24
|
+
tasks?: OAuthToken;
|
|
25
|
+
};
|
|
26
|
+
addedAt: string;
|
|
27
|
+
}
|
|
28
|
+
export interface AccountStore {
|
|
29
|
+
version: 1;
|
|
30
|
+
accounts: GoEasyAccount[];
|
|
31
|
+
}
|
|
32
|
+
export interface OAuthCredentials {
|
|
33
|
+
clientId: string;
|
|
34
|
+
clientSecret: string;
|
|
35
|
+
}
|
|
36
|
+
/** Get the go-easy config directory path */
|
|
37
|
+
export declare function getConfigDir(): string;
|
|
38
|
+
/** Get the pending auth directory path */
|
|
39
|
+
export declare function getPendingDir(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Read the account store. Returns null if it doesn't exist.
|
|
42
|
+
*/
|
|
43
|
+
export declare function readAccountStore(): Promise<AccountStore | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Write the account store atomically.
|
|
46
|
+
* Creates ~/.go-easy/ if needed with correct permissions.
|
|
47
|
+
*/
|
|
48
|
+
export declare function writeAccountStore(store: AccountStore): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Read OAuth credentials (clientId + clientSecret).
|
|
51
|
+
* Returns null if credentials.json doesn't exist.
|
|
52
|
+
*/
|
|
53
|
+
export declare function readCredentials(): Promise<OAuthCredentials | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Write OAuth credentials.
|
|
56
|
+
*/
|
|
57
|
+
export declare function writeCredentials(creds: OAuthCredentials): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Find an account in the store by email (case-insensitive).
|
|
60
|
+
* If no email given, returns the first account.
|
|
61
|
+
*/
|
|
62
|
+
export declare function findAccount(store: AccountStore, email?: string): GoEasyAccount | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the token for a specific service from an account.
|
|
65
|
+
*
|
|
66
|
+
* Priority: combined (if it has the scope) > per-service token.
|
|
67
|
+
*/
|
|
68
|
+
export declare function resolveToken(account: GoEasyAccount, service: GoogleService): {
|
|
69
|
+
refreshToken: string;
|
|
70
|
+
scopes: string[];
|
|
71
|
+
} | null;
|
|
72
|
+
/**
|
|
73
|
+
* Upsert an account in the store. Merges tokens if account exists.
|
|
74
|
+
*/
|
|
75
|
+
export declare function upsertAccount(store: AccountStore, account: GoEasyAccount): AccountStore;
|
|
76
|
+
/**
|
|
77
|
+
* Remove an account from the store by email.
|
|
78
|
+
* Returns true if found and removed.
|
|
79
|
+
*/
|
|
80
|
+
export declare function removeAccount(store: AccountStore, email: string): boolean;
|
|
81
|
+
//# sourceMappingURL=auth-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-store.d.ts","sourceRoot":"","sources":["../src/auth-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QACN,QAAQ,CAAC,EAAE,UAAU,CAAC;QACtB,KAAK,CAAC,EAAE,UAAU,CAAC;QACnB,KAAK,CAAC,EAAE,UAAU,CAAC;QACnB,QAAQ,CAAC,EAAE,UAAU,CAAC;QACtB,KAAK,CAAC,EAAE,UAAU,CAAC;KACpB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAWD,4CAA4C;AAC5C,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,0CAA0C;AAC1C,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAYrE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1E;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAUxE;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAM7E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,YAAY,EACnB,KAAK,CAAC,EAAE,MAAM,GACb,aAAa,GAAG,SAAS,CAM3B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,aAAa,GACrB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAyBnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,aAAa,GACrB,YAAY,CAed;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAQzE"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth store — manages the ~/.go-easy/ token store.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Read/write accounts.json (v1 schema, atomic writes)
|
|
6
|
+
* - File permissions (0o700 dir, 0o600 files)
|
|
7
|
+
* - Provide typed account/token resolution
|
|
8
|
+
*
|
|
9
|
+
* Does NOT handle OAuth flows — that's auth-flow.ts (Phase 2).
|
|
10
|
+
*/
|
|
11
|
+
import { readFile, writeFile, rename, mkdir, chmod } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
import { SCOPES } from './scopes.js';
|
|
15
|
+
// ─── Paths ─────────────────────────────────────────────────
|
|
16
|
+
const GO_EASY_DIR = join(homedir(), '.go-easy');
|
|
17
|
+
const ACCOUNTS_FILE = join(GO_EASY_DIR, 'accounts.json');
|
|
18
|
+
const CREDENTIALS_FILE = join(GO_EASY_DIR, 'credentials.json');
|
|
19
|
+
const PENDING_DIR = join(GO_EASY_DIR, 'pending');
|
|
20
|
+
// ─── Public API ────────────────────────────────────────────
|
|
21
|
+
/** Get the go-easy config directory path */
|
|
22
|
+
export function getConfigDir() {
|
|
23
|
+
return GO_EASY_DIR;
|
|
24
|
+
}
|
|
25
|
+
/** Get the pending auth directory path */
|
|
26
|
+
export function getPendingDir() {
|
|
27
|
+
return PENDING_DIR;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read the account store. Returns null if it doesn't exist.
|
|
31
|
+
*/
|
|
32
|
+
export async function readAccountStore() {
|
|
33
|
+
try {
|
|
34
|
+
const raw = await readFile(ACCOUNTS_FILE, 'utf-8');
|
|
35
|
+
const parsed = JSON.parse(raw);
|
|
36
|
+
if (!parsed || parsed.version !== 1 || !Array.isArray(parsed.accounts)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return parsed;
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (isEnoent(err))
|
|
43
|
+
return null;
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Write the account store atomically.
|
|
49
|
+
* Creates ~/.go-easy/ if needed with correct permissions.
|
|
50
|
+
*/
|
|
51
|
+
export async function writeAccountStore(store) {
|
|
52
|
+
await ensureConfigDir();
|
|
53
|
+
const tmpFile = ACCOUNTS_FILE + '.tmp';
|
|
54
|
+
await writeFile(tmpFile, JSON.stringify(store, null, 2), 'utf-8');
|
|
55
|
+
await safeChmod(tmpFile, 0o600);
|
|
56
|
+
await rename(tmpFile, ACCOUNTS_FILE);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Read OAuth credentials (clientId + clientSecret).
|
|
60
|
+
* Returns null if credentials.json doesn't exist.
|
|
61
|
+
*/
|
|
62
|
+
export async function readCredentials() {
|
|
63
|
+
try {
|
|
64
|
+
const raw = await readFile(CREDENTIALS_FILE, 'utf-8');
|
|
65
|
+
const parsed = JSON.parse(raw);
|
|
66
|
+
if (!parsed?.clientId || !parsed?.clientSecret)
|
|
67
|
+
return null;
|
|
68
|
+
return { clientId: parsed.clientId, clientSecret: parsed.clientSecret };
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (isEnoent(err))
|
|
72
|
+
return null;
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Write OAuth credentials.
|
|
78
|
+
*/
|
|
79
|
+
export async function writeCredentials(creds) {
|
|
80
|
+
await ensureConfigDir();
|
|
81
|
+
const tmpFile = CREDENTIALS_FILE + '.tmp';
|
|
82
|
+
await writeFile(tmpFile, JSON.stringify(creds, null, 2), 'utf-8');
|
|
83
|
+
await safeChmod(tmpFile, 0o600);
|
|
84
|
+
await rename(tmpFile, CREDENTIALS_FILE);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Find an account in the store by email (case-insensitive).
|
|
88
|
+
* If no email given, returns the first account.
|
|
89
|
+
*/
|
|
90
|
+
export function findAccount(store, email) {
|
|
91
|
+
if (!email)
|
|
92
|
+
return store.accounts[0];
|
|
93
|
+
const normalized = email.trim().toLowerCase();
|
|
94
|
+
return store.accounts.find((a) => a.email.toLowerCase() === normalized);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Resolve the token for a specific service from an account.
|
|
98
|
+
*
|
|
99
|
+
* Priority: combined (if it has the scope) > per-service token.
|
|
100
|
+
*/
|
|
101
|
+
export function resolveToken(account, service) {
|
|
102
|
+
const neededScope = SCOPES[service];
|
|
103
|
+
// 1. Try combined token
|
|
104
|
+
if (account.tokens.combined) {
|
|
105
|
+
if (account.tokens.combined.scopes.includes(neededScope)) {
|
|
106
|
+
return {
|
|
107
|
+
refreshToken: account.tokens.combined.refreshToken,
|
|
108
|
+
scopes: account.tokens.combined.scopes,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Combined exists but lacks this scope — don't fall through to per-service
|
|
112
|
+
// (per-service tokens are deleted after upgrade per D1)
|
|
113
|
+
}
|
|
114
|
+
// 2. Try per-service token
|
|
115
|
+
const serviceToken = account.tokens[service];
|
|
116
|
+
if (serviceToken) {
|
|
117
|
+
return {
|
|
118
|
+
refreshToken: serviceToken.refreshToken,
|
|
119
|
+
scopes: serviceToken.scopes,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Upsert an account in the store. Merges tokens if account exists.
|
|
126
|
+
*/
|
|
127
|
+
export function upsertAccount(store, account) {
|
|
128
|
+
const idx = store.accounts.findIndex((a) => a.email.toLowerCase() === account.email.toLowerCase());
|
|
129
|
+
if (idx >= 0) {
|
|
130
|
+
// Merge tokens
|
|
131
|
+
const existing = store.accounts[idx];
|
|
132
|
+
store.accounts[idx] = {
|
|
133
|
+
...existing,
|
|
134
|
+
tokens: { ...existing.tokens, ...account.tokens },
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
store.accounts.push(account);
|
|
139
|
+
}
|
|
140
|
+
return store;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Remove an account from the store by email.
|
|
144
|
+
* Returns true if found and removed.
|
|
145
|
+
*/
|
|
146
|
+
export function removeAccount(store, email) {
|
|
147
|
+
const normalized = email.trim().toLowerCase();
|
|
148
|
+
const idx = store.accounts.findIndex((a) => a.email.toLowerCase() === normalized);
|
|
149
|
+
if (idx < 0)
|
|
150
|
+
return false;
|
|
151
|
+
store.accounts.splice(idx, 1);
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
// ─── Internal helpers ──────────────────────────────────────
|
|
155
|
+
async function ensureConfigDir() {
|
|
156
|
+
try {
|
|
157
|
+
await mkdir(GO_EASY_DIR, { recursive: true });
|
|
158
|
+
await safeChmod(GO_EASY_DIR, 0o700);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Directory already exists
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
await mkdir(PENDING_DIR, { recursive: true });
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// Already exists
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function isEnoent(err) {
|
|
171
|
+
return (typeof err === 'object' &&
|
|
172
|
+
err !== null &&
|
|
173
|
+
'code' in err &&
|
|
174
|
+
err.code === 'ENOENT');
|
|
175
|
+
}
|
|
176
|
+
/** chmod that doesn't throw on Windows (NTFS ACLs ≠ POSIX) */
|
|
177
|
+
async function safeChmod(path, mode) {
|
|
178
|
+
try {
|
|
179
|
+
await chmod(path, mode);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Windows may not support POSIX chmod — best-effort
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=auth-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../src/auth-store.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth module — OAuth2 client factory with multi-account support.
|
|
3
|
+
*
|
|
4
|
+
* Reads tokens from the unified store at ~/.go-easy/accounts.json.
|
|
5
|
+
* Falls back to legacy CLI stores (~/.gmcli, ~/.gdcli, ~/.gccli) via migration.
|
|
6
|
+
*
|
|
7
|
+
* Token resolution per account:
|
|
8
|
+
* 1. combined token (if it has the needed scope) → use it
|
|
9
|
+
* 2. per-service token (legacy migration) → use it
|
|
10
|
+
* 3. neither → AUTH_MISSING_SCOPE with fix command
|
|
11
|
+
*/
|
|
12
|
+
import { OAuth2Client } from 'google-auth-library';
|
|
13
|
+
import type { GoogleService } from './auth-store.js';
|
|
14
|
+
export type { GoogleService } from './auth-store.js';
|
|
15
|
+
/**
|
|
16
|
+
* Get an OAuth2Client for a specific service and account.
|
|
17
|
+
*
|
|
18
|
+
* @param service - Which Google service (determines scope check)
|
|
19
|
+
* @param account - Email address (defaults to first account in the store)
|
|
20
|
+
* @returns Configured OAuth2Client with refresh token set
|
|
21
|
+
* @throws AuthError with specific code and fix command
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { getAuth } from '@marcfargas/go-easy/auth';
|
|
26
|
+
* const auth = await getAuth('gmail', 'marc@blegal.eu');
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function getAuth(service: GoogleService, account?: string): Promise<OAuth2Client>;
|
|
30
|
+
/**
|
|
31
|
+
* List available accounts (emails) for a service.
|
|
32
|
+
* Only returns accounts that have a token for the given service.
|
|
33
|
+
*/
|
|
34
|
+
export declare function listAccounts(service: GoogleService): Promise<string[]>;
|
|
35
|
+
/**
|
|
36
|
+
* List all accounts regardless of service.
|
|
37
|
+
*/
|
|
38
|
+
export declare function listAllAccounts(): Promise<Array<{
|
|
39
|
+
email: string;
|
|
40
|
+
scopes: string[];
|
|
41
|
+
source: string;
|
|
42
|
+
}>>;
|
|
43
|
+
/**
|
|
44
|
+
* Clear the client cache. Useful for tests or token rotation.
|
|
45
|
+
*/
|
|
46
|
+
export declare function clearAuthCache(): void;
|
|
47
|
+
//# sourceMappingURL=auth.d.ts.map
|