dorky 2.2.2 → 2.3.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.
Files changed (3) hide show
  1. package/README.md +11 -6
  2. package/bin/index.js +121 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -87,10 +87,15 @@ Anyhow, we shall store it on a private storage, using **dorky**, that stores it
87
87
  [*] List remote files in dorky bucket.
88
88
  [*] Auto detect .env and .config files.
89
89
  [*] Update node version to latest LTS.
90
- [ ] Handle errors.
91
- [ ] Extension for VS Code to list and highlight them like git.
92
- [ ] Unintialize dorky setup.
93
- [ ] MCP server.
94
- [ ] Encryption of files.
95
- [ ] Add stages for variables.
90
+ [*] Ignore dorky files in dorky itself.
91
+ [*] Update .gitignore automatically, to ignore .dorky/credentials.json.
92
+ [*] Handle reauthentication loop for google-drive. (Bug fix release)
93
+ [ ] Fix error while adding a file that does not exist, it does give an error but still prints that an entry is added.
94
+ [ ] Fix issue when the file is added again with the same contents, it still adds it, not checks it with the hash.
95
+ [ ] Handle invalid access token for google-drive.
96
+ [ ] Extension for VS Code to list and highlight them like git. (Major release)
97
+ [ ] Unintialize dorky setup. (Bug fix release)
98
+ [ ] MCP server. (Minor release)
99
+ [ ] Encryption of files. (Minor release)
100
+ [ ] Add stages for variables. (Major release)
96
101
 
package/bin/index.js CHANGED
@@ -86,24 +86,114 @@ function setupFilesAndFolders(metaData, credentials) {
86
86
  }
87
87
  }
88
88
 
89
- async function authorizeGoogleDriveClient() {
89
+ function updateGitIgnore() {
90
+ let gitignoreContent = "";
91
+ if (existsSync(".gitignore")) {
92
+ gitignoreContent = fs.readFileSync(".gitignore").toString();
93
+ }
94
+ const dorkyIgnoreEntry = ".dorky/credentials.json";
95
+ if (!gitignoreContent.includes(dorkyIgnoreEntry)) {
96
+ gitignoreContent += EOL + dorkyIgnoreEntry + EOL;
97
+ fs.writeFileSync(".gitignore", gitignoreContent);
98
+ console.log(`${chalk.bgGreen("Updated .gitignore to ignore .dorky/credentials.json.")} ${chalk.red("⚠️ This is done to protect your credentials.")}`);
99
+ }
100
+ }
101
+
102
+ async function authorizeGoogleDriveClient(forceReauth = false) {
90
103
  async function loadSavedCredentialsIfExist() {
91
104
  try {
92
105
  const content = await fs.readFileSync(TOKEN_PATH);
93
- const credentials = JSON.parse(content);
94
- return google.auth.fromJSON(credentials);
106
+ const savedCredentials = JSON.parse(content);
107
+
108
+ // Check if this is OAuth2 credentials (has access_token, refresh_token, etc.)
109
+ if (!savedCredentials.access_token && !savedCredentials.refresh_token) {
110
+ return null;
111
+ }
112
+
113
+ // Load the client secrets to create an OAuth2 client
114
+ const keys = JSON.parse(fs.readFileSync(CREDENTIALS_PATH));
115
+ const key = keys.installed || keys.web;
116
+ const oAuth2Client = new google.auth.OAuth2(
117
+ key.client_id,
118
+ key.client_secret,
119
+ key.redirect_uris[0]
120
+ );
121
+
122
+ // Remove the 'storage' field and set credentials
123
+ const { storage, ...authCredentials } = savedCredentials;
124
+ oAuth2Client.setCredentials(authCredentials);
125
+
126
+ return oAuth2Client;
95
127
  } catch (err) {
96
128
  return null;
97
129
  }
98
130
  }
99
- let client = await loadSavedCredentialsIfExist();
100
- if (client) {
101
- return client;
131
+
132
+ async function isTokenExpired(credentials) {
133
+ if (!credentials.expiry_date) {
134
+ return true;
135
+ }
136
+ // Both Date.now() and expiry_date are in milliseconds since Unix epoch (UTC)
137
+ // Check if token expires in less than 5 minutes (300000 ms)
138
+ const expiryBuffer = 300000;
139
+ const currentTimeUTC = Date.now();
140
+ const expiryTimeUTC = credentials.expiry_date;
141
+
142
+ // Token is expired if current time is past (expiry time - buffer)
143
+ return currentTimeUTC >= (expiryTimeUTC - expiryBuffer);
144
+ }
145
+
146
+ async function refreshAndSaveToken(client) {
147
+ try {
148
+ await client.getAccessToken();
149
+ const newCredentials = client.credentials;
150
+ const credentialsToSave = {
151
+ storage: "google-drive",
152
+ ...newCredentials
153
+ };
154
+ fs.writeFileSync(TOKEN_PATH, JSON.stringify(credentialsToSave, null, 2));
155
+ return client;
156
+ } catch (err) {
157
+ return null;
158
+ }
102
159
  }
160
+
161
+ // If not forcing reauth, try to load existing credentials
162
+ if (!forceReauth) {
163
+ let client = await loadSavedCredentialsIfExist();
164
+ if (client) {
165
+ const credentials = JSON.parse(fs.readFileSync(TOKEN_PATH));
166
+
167
+ // Ensure we're using the client's credentials which may have been updated
168
+ const clientCredentials = client.credentials || credentials;
169
+
170
+ if (await isTokenExpired(clientCredentials)) {
171
+ client = await refreshAndSaveToken(client);
172
+ if (client) {
173
+ return client;
174
+ }
175
+ // If refresh failed, fall through to full reauth
176
+ } else {
177
+ return client;
178
+ }
179
+ }
180
+ }
181
+
182
+ // Perform full authentication
103
183
  client = await authenticate({
104
184
  scopes: SCOPES,
105
185
  keyfilePath: CREDENTIALS_PATH,
106
186
  });
187
+
188
+ // Save credentials after full authentication
189
+ if (client && client.credentials) {
190
+ const credentialsToSave = {
191
+ storage: "google-drive",
192
+ ...client.credentials
193
+ };
194
+ fs.writeFileSync(TOKEN_PATH, JSON.stringify(credentialsToSave, null, 2));
195
+ }
196
+
107
197
  return client;
108
198
  }
109
199
 
@@ -116,7 +206,7 @@ async function init(storage) {
116
206
  setupFilesAndFolders(metaData, credentials);
117
207
  break;
118
208
  case "google-drive":
119
- const client = await authorizeGoogleDriveClient();
209
+ const client = await authorizeGoogleDriveClient(true); // Force reauth on init
120
210
  credentials = { storage: "google-drive", ...client.credentials };
121
211
  setupFilesAndFolders(metaData, credentials);
122
212
  break;
@@ -124,6 +214,7 @@ async function init(storage) {
124
214
  console.log("Please provide a valid storage option <aws|google-drive>");
125
215
  break;
126
216
  }
217
+ updateGitIgnore();
127
218
  }
128
219
 
129
220
  async function list(type) {
@@ -149,6 +240,9 @@ async function list(type) {
149
240
  for (let i = 0; i < exclusions.length; i++) {
150
241
  if (file.includes(exclusions[i])) return false;
151
242
  }
243
+ if (file.includes(".dorky/")) return false;
244
+ if (file.endsWith(".dorky") && fs.lstatSync(file).isDirectory()) return false;
245
+ if (file.endsWith(".dorkyignore")) return false;
152
246
  return true;
153
247
  });
154
248
  filteredFiles.forEach((file) => {
@@ -225,7 +319,7 @@ async function checkCredentials() {
225
319
  } else {
226
320
  try {
227
321
  let credentials;
228
- const client = await authorizeGoogleDriveClient();
322
+ const client = await authorizeGoogleDriveClient(true); // Force reauth when creating new credentials
229
323
  credentials = { storage: "google-drive", ...client.credentials };
230
324
  fs.writeFileSync(".dorky/credentials.json", JSON.stringify(credentials, null, 2));
231
325
  console.log(chalk.green("Credentials saved in .dorky/credentials.json"));
@@ -281,7 +375,7 @@ async function push() {
281
375
  }
282
376
  metaData["uploaded-files"] = metaData["stage-1-files"];
283
377
  fs.writeFileSync(".dorky/metadata.json", JSON.stringify(metaData, null, 2));
284
- console.log(chalk.green("Pushed files to storage"));
378
+ console.log(chalk.green("Pushed the following files to storage:"));
285
379
  }
286
380
 
287
381
  function pushToS3(files, credentials) {
@@ -336,7 +430,15 @@ async function pushToGoogleDrive(files) {
336
430
  return parentId;
337
431
  }
338
432
  console.log("Uploading to google drive");
339
- const client = await authorizeGoogleDriveClient();
433
+ const client = await authorizeGoogleDriveClient(false); // Use existing token if valid
434
+
435
+ // Update credentials file with potentially refreshed token
436
+ const credentialsToSave = {
437
+ storage: "google-drive",
438
+ ...client.credentials
439
+ };
440
+ fs.writeFileSync(TOKEN_PATH, JSON.stringify(credentialsToSave, null, 2));
441
+
340
442
  const drive = google.drive({ version: 'v3', auth: client });
341
443
  for (const file of files) {
342
444
  const rootFolder = path.basename(process.cwd());
@@ -419,7 +521,15 @@ async function pullFromGoogleDrive(files) {
419
521
  return { name: file, ...files[file] };
420
522
  });
421
523
 
422
- const client = await authorizeGoogleDriveClient();
524
+ const client = await authorizeGoogleDriveClient(false); // Use existing token if valid
525
+
526
+ // Update credentials file with potentially refreshed token
527
+ const credentialsToSave = {
528
+ storage: "google-drive",
529
+ ...client.credentials
530
+ };
531
+ fs.writeFileSync(TOKEN_PATH, JSON.stringify(credentialsToSave, null, 2));
532
+
423
533
  const drive = google.drive({ version: "v3", auth: client });
424
534
  try {
425
535
  files.map(async (file) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dorky",
3
- "version": "2.2.2",
3
+ "version": "2.3.3",
4
4
  "description": "DevOps Records Keeper.",
5
5
  "bin": {
6
6
  "dorky": "bin/index.js"