@mcpher/gas-fakes 1.2.32 → 2.0.1
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/.gcloudignore +24 -0
- package/README.md +5 -5
- package/appsscript.json +101 -0
- package/exgcp.sh +4 -4
- package/package.json +5 -6
- package/src/cli/app.js +9 -1
- package/src/cli/lib-manager.js +0 -1
- package/src/cli/setup.js +330 -228
- package/src/services/advcalendar/clapis.js +4 -2
- package/src/services/advdocs/docapis.js +4 -3
- package/src/services/advdrive/drapis.js +8 -5
- package/src/services/advforms/formsapis.js +4 -3
- package/src/services/advgmail/gmailapis.js +4 -3
- package/src/services/advsheets/shapis.js +5 -10
- package/src/services/advslides/slapis.js +4 -3
- package/src/services/driveapp/fakedriveapp.js +10 -2
- package/src/services/logger/fakelogger.js +6 -3
- package/src/services/scriptapp/app.js +16 -11
- package/src/services/scriptapp/behavior.js +132 -107
- package/src/services/session/fakesession.js +24 -9
- package/src/services/slidesapp/fakepresentation.js +19 -8
- package/src/services/slidesapp/fakeslide.js +45 -20
- package/src/services/spreadsheetapp/fakesheet.js +9 -7
- package/src/services/stores/fakestores.js +20 -18
- package/src/services/stores/gasflex.js +13 -14
- package/src/services/urlfetchapp/app.js +3 -3
- package/src/support/auth.js +227 -55
- package/src/support/slogger.js +42 -0
- package/src/support/sxauth.js +42 -39
- package/src/support/sxcalendar.js +9 -43
- package/src/support/sxdocs.js +6 -42
- package/src/support/sxdrive.js +19 -76
- package/src/support/sxfetch.js +36 -30
- package/src/support/sxforms.js +9 -40
- package/src/support/sxgmail.js +9 -37
- package/src/support/sxretry.js +79 -0
- package/src/support/sxsheets.js +6 -37
- package/src/support/sxslides.js +5 -36
- package/src/support/sxtoken.js +15 -0
- package/src/support/syncit.js +27 -10
- package/src/support/workersync/sxfunctions.js +2 -0
- package/src/support/workersync/synclogger.js +22 -5
- package/src/support/workersync/worker.js +8 -11
- package/README.RU.md +0 -373
- package/env.setup.template +0 -16
- package/run.js +0 -35
- package/setup.js +0 -689
- package/src/Code.js +0 -3
- package/src/appsscript.json +0 -5
package/src/cli/setup.js
CHANGED
|
@@ -41,6 +41,16 @@ async function findEnvFiles(dir) {
|
|
|
41
41
|
export async function initializeConfiguration(options = {}) {
|
|
42
42
|
let envPath;
|
|
43
43
|
|
|
44
|
+
// first step is to check we have a manifest file if we are doing auth type dwd
|
|
45
|
+
if (options.authType === "dwd") {
|
|
46
|
+
const manifestPath = path.resolve(process.cwd(), "appsscript.json");
|
|
47
|
+
if (!fs.existsSync(manifestPath)) {
|
|
48
|
+
console.log("No manifest file found. Please create an appsscript.json file in the current directory with required scopes.");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// need to figure out which env file we are operating on
|
|
44
54
|
if (options.env) {
|
|
45
55
|
envPath = path.resolve(process.cwd(), options.env);
|
|
46
56
|
console.log(`-> Using specified .env path: ${envPath}`);
|
|
@@ -90,23 +100,57 @@ export async function initializeConfiguration(options = {}) {
|
|
|
90
100
|
existingConfig = dotenv.parse(fs.readFileSync(envPath));
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
const responses = {};
|
|
104
|
+
const DEFAULT_SCOPES_VALUES = [
|
|
105
|
+
"https://www.googleapis.com/auth/userinfo.email",
|
|
106
|
+
"openid",
|
|
107
|
+
"https://www.googleapis.com/auth/cloud-platform",
|
|
108
|
+
];
|
|
109
|
+
console.log(
|
|
110
|
+
"\nThe following default scopes are required for basic operations and will be enabled automatically:"
|
|
111
|
+
);
|
|
112
|
+
DEFAULT_SCOPES_VALUES.forEach((scope) => console.log(` - ${scope}`));
|
|
113
|
+
responses.DEFAULT_SCOPES = DEFAULT_SCOPES_VALUES;
|
|
114
|
+
|
|
115
|
+
if (options.authType === "dwd") {
|
|
116
|
+
responses.AUTH_TYPE = "dwd";
|
|
117
|
+
// we need to get the scopes from the manifest file
|
|
118
|
+
const manifestPath = path.resolve(process.cwd(), "appsscript.json");
|
|
119
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath));
|
|
120
|
+
const scopes = manifest?.oauthScopes;
|
|
121
|
+
// remove any in manifest that are default anyway
|
|
122
|
+
responses.EXTRA_SCOPES = (scopes || []).filter(scope => !DEFAULT_SCOPES_VALUES.includes(scope));
|
|
123
|
+
|
|
124
|
+
// if we are doing dwd we need to ask for the service account name
|
|
125
|
+
const serviceAccountNameQuestion = {
|
|
126
|
+
type: "text",
|
|
127
|
+
name: "GOOGLE_SERVICE_ACCOUNT_NAME",
|
|
128
|
+
message: "Enter a service account name (it will be created if it doesnt already exist)",
|
|
129
|
+
initial: existingConfig.GOOGLE_SERVICE_ACCOUNT_NAME || "gas-fakes-sa",
|
|
130
|
+
};
|
|
131
|
+
const serviceAccountNameResponse = await prompts(serviceAccountNameQuestion);
|
|
132
|
+
if (typeof serviceAccountNameResponse.GOOGLE_SERVICE_ACCOUNT_NAME === "undefined") {
|
|
133
|
+
console.log("Initialization cancelled.");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
Object.assign(responses, serviceAccountNameResponse);
|
|
137
|
+
} else {
|
|
138
|
+
responses.AUTH_TYPE = "adc";
|
|
139
|
+
console.log("--------------------------------------------------");
|
|
140
|
+
console.log("Configuring .env for gas-fakes");
|
|
141
|
+
console.log("Press Enter to accept the default value in brackets.");
|
|
142
|
+
console.log("Use Space to select/deselect scopes.");
|
|
143
|
+
console.log("--------------------------------------------------");
|
|
144
|
+
}
|
|
145
|
+
|
|
98
146
|
|
|
99
|
-
const existingExtraScopes = existingConfig.EXTRA_SCOPES
|
|
100
|
-
? existingConfig.EXTRA_SCOPES.split(",").filter((s) => s)
|
|
101
|
-
: [];
|
|
102
147
|
|
|
103
|
-
const responses = {};
|
|
104
148
|
|
|
105
149
|
// --- Stage 1: Basic Info ---
|
|
106
150
|
const basicInfoQuestions = [
|
|
107
151
|
{
|
|
108
152
|
type: "text",
|
|
109
|
-
name: "
|
|
153
|
+
name: "GOOGLE_CLOUD_PROJECT",
|
|
110
154
|
message: "Enter your GCP Project ID",
|
|
111
155
|
initial:
|
|
112
156
|
existingConfig.GCP_PROJECT_ID || process.env.GOOGLE_CLOUD_PROJECT,
|
|
@@ -121,7 +165,7 @@ export async function initializeConfiguration(options = {}) {
|
|
|
121
165
|
];
|
|
122
166
|
|
|
123
167
|
const basicInfoResponses = await prompts(basicInfoQuestions);
|
|
124
|
-
if (typeof basicInfoResponses.
|
|
168
|
+
if (typeof basicInfoResponses.GOOGLE_CLOUD_PROJECT === "undefined") {
|
|
125
169
|
console.log("Initialization cancelled.");
|
|
126
170
|
return;
|
|
127
171
|
}
|
|
@@ -129,153 +173,125 @@ export async function initializeConfiguration(options = {}) {
|
|
|
129
173
|
|
|
130
174
|
// --- Stage 2: Scopes ---
|
|
131
175
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
{
|
|
190
|
-
sensitivity: "sensitive",
|
|
191
|
-
title: "Gmail modify",
|
|
192
|
-
value: "https://www.googleapis.com/auth/gmail.modify",
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
sensitivity: "sensitive",
|
|
196
|
-
title: "Gmail send",
|
|
197
|
-
value: "https://www.googleapis.com/auth/gmail.send",
|
|
198
|
-
},
|
|
199
|
-
].map((scope) => ({
|
|
200
|
-
...scope,
|
|
201
|
-
title: scope.sensitivity
|
|
202
|
-
? `[${scope.sensitivity}] ${scope.title}`
|
|
203
|
-
: scope.title,
|
|
204
|
-
// because we always need drive for ant extra scopes
|
|
205
|
-
selected:
|
|
206
|
-
existingExtraScopes.length > 0
|
|
207
|
-
? existingExtraScopes.includes(scope.value)
|
|
208
|
-
: scope.value === "https://www.googleapis.com/auth/drive",
|
|
209
|
-
})),
|
|
210
|
-
hint: "- Use space to select/deselect. Press Enter to submit.",
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// Check for any kind of sensitivity
|
|
214
|
-
const sensitiveScopesList = extraScopeQuestion.choices.filter(
|
|
215
|
-
(scope) => scope.sensitivity
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
const extraScopeResponses = await prompts(extraScopeQuestion);
|
|
176
|
+
// we only need this if we doing adc
|
|
177
|
+
if (options.authType === "adc") {
|
|
178
|
+
const existingExtraScopes = existingConfig.EXTRA_SCOPES
|
|
179
|
+
? existingConfig.EXTRA_SCOPES.split(",").filter((s) => s)
|
|
180
|
+
: [];
|
|
181
|
+
const extraScopeQuestion = {
|
|
182
|
+
type: "multiselect",
|
|
183
|
+
name: "EXTRA_SCOPES",
|
|
184
|
+
message: "Select any extra scopes your script requires",
|
|
185
|
+
choices: [
|
|
186
|
+
{
|
|
187
|
+
title: "Workspace resources",
|
|
188
|
+
value: "https://www.googleapis.com/auth/drive",
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
sensitivity: "sensitive",
|
|
192
|
+
title: "Calendar (full access)",
|
|
193
|
+
value: "https://www.googleapis.com/auth/calendar",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
// actually labels are not sensitive
|
|
197
|
+
title: "Gmail labels",
|
|
198
|
+
value: "https://www.googleapis.com/auth/gmail.labels",
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
sensitivity: "sensitive",
|
|
202
|
+
title: "Gmail compose",
|
|
203
|
+
value: "https://www.googleapis.com/auth/gmail.compose",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
sensitivity: "sensitive",
|
|
207
|
+
title: "Gmail modify",
|
|
208
|
+
value: "https://www.googleapis.com/auth/gmail.modify",
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
sensitivity: "sensitive",
|
|
212
|
+
title: "Gmail send",
|
|
213
|
+
value: "https://www.googleapis.com/auth/gmail.send",
|
|
214
|
+
},
|
|
215
|
+
].map((scope) => ({
|
|
216
|
+
...scope,
|
|
217
|
+
title: scope.sensitivity
|
|
218
|
+
? `[${scope.sensitivity}] ${scope.title}`
|
|
219
|
+
: scope.title,
|
|
220
|
+
// because we always need drive for ant extra scopes
|
|
221
|
+
selected:
|
|
222
|
+
existingExtraScopes.length > 0
|
|
223
|
+
? existingExtraScopes.includes(scope.value)
|
|
224
|
+
: scope.value === "https://www.googleapis.com/auth/drive",
|
|
225
|
+
})),
|
|
226
|
+
hint: "- Use space to select/deselect. Press Enter to submit.",
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// Check for any kind of sensitivity
|
|
230
|
+
const sensitiveScopesList = extraScopeQuestion.choices.filter(
|
|
231
|
+
(scope) => scope.sensitivity
|
|
232
|
+
);
|
|
219
233
|
|
|
220
|
-
|
|
221
|
-
console.log("Initialization cancelled.");
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
Object.assign(responses, extraScopeResponses);
|
|
234
|
+
const extraScopeResponses = options.authType === "adc" ? await prompts(extraScopeQuestion) : {};
|
|
225
235
|
|
|
226
|
-
|
|
236
|
+
if (typeof extraScopeResponses.EXTRA_SCOPES === "undefined") {
|
|
237
|
+
console.log("Initialization cancelled.");
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
Object.assign(responses, extraScopeResponses);
|
|
227
241
|
|
|
228
|
-
|
|
229
|
-
selectedExtraScopes.includes(s.value)
|
|
230
|
-
);
|
|
242
|
+
const selectedExtraScopes = responses.EXTRA_SCOPES || [];
|
|
231
243
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
console.log(
|
|
235
|
-
"You have selected sensitive or restricted scopes. Google requires an OAuth client credential file for these."
|
|
236
|
-
);
|
|
237
|
-
console.log(
|
|
238
|
-
"See the getting started guide https://github.com/brucemcpherson/gas-fakes/blob/main/GETTING_STARTED.md for how."
|
|
244
|
+
const usesSensitiveScopes = sensitiveScopesList.some((s) =>
|
|
245
|
+
selectedExtraScopes.includes(s.value)
|
|
239
246
|
);
|
|
240
|
-
console.log("--------------------------------------------------");
|
|
241
|
-
}
|
|
242
247
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
248
|
+
if (usesSensitiveScopes) {
|
|
249
|
+
console.log("\n--------------------------------------------------");
|
|
250
|
+
console.log(
|
|
251
|
+
"You have selected sensitive or restricted scopes. Google requires an OAuth client credential file for these."
|
|
252
|
+
);
|
|
253
|
+
console.log(
|
|
254
|
+
"See the getting started guide https://github.com/brucemcpherson/gas-fakes/blob/main/GETTING_STARTED.md for how."
|
|
255
|
+
);
|
|
256
|
+
console.log("--------------------------------------------------");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const clientCredentialQuestion = {
|
|
260
|
+
type: "text",
|
|
261
|
+
name: "CLIENT_CREDENTIAL_FILE",
|
|
262
|
+
message: usesSensitiveScopes
|
|
263
|
+
? "Enter the path and filename for your OAuth client credentials JSON"
|
|
264
|
+
: "Enter path to OAuth client credentials JSON (optional)",
|
|
265
|
+
initial: existingConfig.CLIENT_CREDENTIAL_FILE || "",
|
|
266
|
+
validate: (input) => {
|
|
267
|
+
const trimmedInput = input.trim();
|
|
268
|
+
|
|
269
|
+
if (usesSensitiveScopes) {
|
|
270
|
+
if (trimmedInput === "") {
|
|
271
|
+
return "This field is required for the selected sensitive scopes.";
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
if (trimmedInput === "") {
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
260
277
|
}
|
|
261
|
-
}
|
|
262
278
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
279
|
+
const resolvedPath = path.resolve(process.cwd(), trimmedInput);
|
|
280
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
281
|
+
return `File not found at '${resolvedPath}'. Please check the path and try again.`;
|
|
282
|
+
}
|
|
267
283
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
284
|
+
return true;
|
|
285
|
+
},
|
|
286
|
+
};
|
|
271
287
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
288
|
+
const clientCredentialResponse = await prompts(clientCredentialQuestion);
|
|
289
|
+
if (typeof clientCredentialResponse.CLIENT_CREDENTIAL_FILE === "undefined") {
|
|
290
|
+
console.log("Initialization cancelled.");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
Object.assign(responses, clientCredentialResponse);
|
|
276
294
|
}
|
|
277
|
-
Object.assign(responses, clientCredentialResponse);
|
|
278
|
-
|
|
279
295
|
// --- Stage 3: Remaining Config ---
|
|
280
296
|
const defaultScopesDisplay = `\n - Default: [${responses.DEFAULT_SCOPES.join(
|
|
281
297
|
", "
|
|
@@ -285,6 +301,7 @@ export async function initializeConfiguration(options = {}) {
|
|
|
285
301
|
? `\n - Extra: [${responses.EXTRA_SCOPES.join(", ")}]`
|
|
286
302
|
: "\n - Extra: [None]";
|
|
287
303
|
|
|
304
|
+
|
|
288
305
|
const remainingQuestions = [
|
|
289
306
|
{
|
|
290
307
|
type: "toggle",
|
|
@@ -307,8 +324,8 @@ export async function initializeConfiguration(options = {}) {
|
|
|
307
324
|
existingConfig.LOG_DESTINATION
|
|
308
325
|
) > -1
|
|
309
326
|
? ["CONSOLE", "CLOUD", "BOTH", "NONE"].indexOf(
|
|
310
|
-
|
|
311
|
-
|
|
327
|
+
existingConfig.LOG_DESTINATION
|
|
328
|
+
)
|
|
312
329
|
: 0,
|
|
313
330
|
},
|
|
314
331
|
{
|
|
@@ -321,7 +338,7 @@ export async function initializeConfiguration(options = {}) {
|
|
|
321
338
|
],
|
|
322
339
|
initial:
|
|
323
340
|
["FILE", "UPSTASH"].indexOf(existingConfig.STORE_TYPE?.toUpperCase()) >
|
|
324
|
-
|
|
341
|
+
-1
|
|
325
342
|
? ["FILE", "UPSTASH"].indexOf(existingConfig.STORE_TYPE.toUpperCase())
|
|
326
343
|
: 0,
|
|
327
344
|
},
|
|
@@ -414,6 +431,7 @@ export async function initializeConfiguration(options = {}) {
|
|
|
414
431
|
* Handles the 'auth' command to authenticate with Google Cloud.
|
|
415
432
|
*/
|
|
416
433
|
export async function authenticateUser() {
|
|
434
|
+
|
|
417
435
|
// First, check if gcloud CLI is available.
|
|
418
436
|
await checkForGcloudCli();
|
|
419
437
|
|
|
@@ -429,18 +447,30 @@ export async function authenticateUser() {
|
|
|
429
447
|
dotenv.config({ path: envPath, quiet: true });
|
|
430
448
|
|
|
431
449
|
const {
|
|
450
|
+
// still supported for backwards compatibility
|
|
432
451
|
GCP_PROJECT_ID,
|
|
452
|
+
|
|
453
|
+
GOOGLE_CLOUD_PROJECT,
|
|
454
|
+
|
|
455
|
+
// the scopes would have been set up in the init process whether or not they came form the manifest
|
|
433
456
|
DEFAULT_SCOPES,
|
|
434
457
|
EXTRA_SCOPES,
|
|
458
|
+
|
|
459
|
+
// this would be required for sensitive scopes if using adc
|
|
435
460
|
CLIENT_CREDENTIAL_FILE,
|
|
436
461
|
AC,
|
|
462
|
+
AUTH_TYPE,
|
|
463
|
+
GOOGLE_SERVICE_ACCOUNT_NAME
|
|
437
464
|
} = process.env;
|
|
438
465
|
|
|
439
|
-
|
|
440
|
-
|
|
466
|
+
const projectId = GOOGLE_CLOUD_PROJECT || GCP_PROJECT_ID;
|
|
467
|
+
if (!projectId) {
|
|
468
|
+
console.error("Error: GOOGLE_CLOUD_PROJECT is not set in your .env file.");
|
|
441
469
|
process.exit(1);
|
|
442
470
|
}
|
|
443
471
|
|
|
472
|
+
// question for Kanshi -- why all this stuff? it's all in the .env file....
|
|
473
|
+
/*
|
|
444
474
|
const defaultScopes =
|
|
445
475
|
DEFAULT_SCOPES ||
|
|
446
476
|
"https://www.googleapis.com/auth/userinfo.email,openid,https://www.googleapis.com/auth/cloud-platform";
|
|
@@ -452,73 +482,79 @@ export async function authenticateUser() {
|
|
|
452
482
|
if (extraScopes && extraScopes.length > 0) {
|
|
453
483
|
scopes += (extraScopes.startsWith(",") ? "" : ",") + extraScopes;
|
|
454
484
|
}
|
|
455
|
-
|
|
485
|
+
*/
|
|
486
|
+
const scopes = Array.from(new Set([DEFAULT_SCOPES.split(",").concat(EXTRA_SCOPES.split(","))].filter(d => d))).join(",")
|
|
456
487
|
const driveAccessFlag = "--enable-gdrive-access";
|
|
457
488
|
|
|
458
489
|
console.log(`...requesting scopes ${scopes}`);
|
|
459
490
|
|
|
460
491
|
let clientFlag = "";
|
|
461
|
-
|
|
462
|
-
|
|
492
|
+
const activeConfig = AC || "default";
|
|
493
|
+
//--- specific to adc auth type
|
|
494
|
+
if (AUTH_TYPE === "adc") {
|
|
463
495
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
496
|
+
if (CLIENT_CREDENTIAL_FILE) {
|
|
497
|
+
console.log("...attempting to use enhanced client credentials");
|
|
498
|
+
|
|
499
|
+
let clientPath = CLIENT_CREDENTIAL_FILE;
|
|
500
|
+
if (!path.isAbsolute(clientPath)) {
|
|
501
|
+
clientPath = path.join(rootDirectory, clientPath);
|
|
502
|
+
}
|
|
468
503
|
|
|
469
|
-
|
|
470
|
-
|
|
504
|
+
if (fs.existsSync(clientPath)) {
|
|
505
|
+
clientFlag = `--client-id-file="${clientPath}"`;
|
|
506
|
+
} else {
|
|
507
|
+
console.error(
|
|
508
|
+
`Error: Client credential file specified in .env not found at '${clientPath}'`
|
|
509
|
+
);
|
|
510
|
+
process.exit(1);
|
|
511
|
+
}
|
|
471
512
|
} else {
|
|
472
|
-
console.
|
|
473
|
-
|
|
513
|
+
console.log(
|
|
514
|
+
"\n...CLIENT_CREDENTIAL_FILE is not set. Using default Application Default Credentials (ADC)."
|
|
515
|
+
);
|
|
516
|
+
console.log(
|
|
517
|
+
"...if you have requested any sensitive scopes, you'll see 'This app is blocked message.'"
|
|
518
|
+
);
|
|
519
|
+
console.log(
|
|
520
|
+
"...To allow them see - https://github.com/brucemcpherson/gas-fakes/blob/main/GETTING_STARTED.md\n"
|
|
474
521
|
);
|
|
475
|
-
process.exit(1);
|
|
476
522
|
}
|
|
477
|
-
} else {
|
|
478
|
-
console.log(
|
|
479
|
-
"\n...CLIENT_CREDENTIAL_FILE is not set. Using default Application Default Credentials (ADC)."
|
|
480
|
-
);
|
|
481
|
-
console.log(
|
|
482
|
-
"...if you have requested any sensitive scopes, you'll see 'This app is blocked message.'"
|
|
483
|
-
);
|
|
484
|
-
console.log(
|
|
485
|
-
"...To allow them see - https://github.com/brucemcpherson/gas-fakes/blob/main/GETTING_STARTED.md\n"
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
523
|
|
|
489
|
-
const projectId = GCP_PROJECT_ID;
|
|
490
|
-
const activeConfig = AC || "default";
|
|
491
524
|
|
|
492
|
-
console.log("Revoking previous credentials...");
|
|
493
|
-
try {
|
|
494
|
-
execSync("gcloud auth revoke --quiet", { stdio: "ignore", shell: true });
|
|
495
|
-
} catch (e) {
|
|
496
|
-
/* ignore */
|
|
497
|
-
}
|
|
498
|
-
try {
|
|
499
|
-
execSync("gcloud auth application-default revoke --quiet", {
|
|
500
|
-
stdio: "ignore",
|
|
501
|
-
shell: true,
|
|
502
|
-
});
|
|
503
|
-
} catch (e) {
|
|
504
|
-
/* ignore */
|
|
505
|
-
}
|
|
506
525
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
526
|
+
console.log("Revoking previous credentials...");
|
|
527
|
+
try {
|
|
528
|
+
execSync("gcloud auth revoke --quiet", { stdio: "ignore", shell: true });
|
|
529
|
+
} catch (e) {
|
|
530
|
+
/* ignore */
|
|
531
|
+
}
|
|
532
|
+
try {
|
|
533
|
+
execSync("gcloud auth application-default revoke --quiet", {
|
|
534
|
+
stdio: "ignore",
|
|
535
|
+
shell: true,
|
|
536
|
+
});
|
|
537
|
+
} catch (e) {
|
|
538
|
+
/* ignore */
|
|
539
|
+
}
|
|
518
540
|
|
|
519
|
-
|
|
520
|
-
|
|
541
|
+
console.log(`Ensuring gcloud configuration '${activeConfig}' exists...`);
|
|
542
|
+
try {
|
|
543
|
+
execSync(`gcloud config configurations describe "${activeConfig}"`, {
|
|
544
|
+
stdio: "ignore",
|
|
545
|
+
shell: true,
|
|
546
|
+
});
|
|
547
|
+
console.log(`Configuration '${activeConfig}' already exists.`);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
console.log(`Configuration '${activeConfig}' not found. Creating it...`);
|
|
550
|
+
runCommandSync(`gcloud config configurations create "${activeConfig}"`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
console.log(`Activating gcloud configuration: ${activeConfig}`);
|
|
554
|
+
runCommandSync(`gcloud config configurations activate "${activeConfig}"`);
|
|
555
|
+
}
|
|
521
556
|
|
|
557
|
+
//--- need this for both auth types
|
|
522
558
|
console.log(`Setting project to: ${projectId}`);
|
|
523
559
|
runCommandSync(`gcloud config set project ${projectId}`);
|
|
524
560
|
runCommandSync(`gcloud config set billing/quota_project ${projectId}`);
|
|
@@ -546,36 +582,89 @@ export async function authenticateUser() {
|
|
|
546
582
|
process.exit(1);
|
|
547
583
|
}
|
|
548
584
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
585
|
+
//--- specific to adc auth type
|
|
586
|
+
if (AUTH_TYPE === "adc") {
|
|
587
|
+
console.log("Initiating Application Default Credentials (ADC) login...");
|
|
588
|
+
runCommandSync(
|
|
589
|
+
`gcloud auth application-default login --scopes="${scopes}" ${clientFlag}`
|
|
590
|
+
);
|
|
591
|
+
runCommandSync(
|
|
592
|
+
`gcloud auth application-default set-quota-project ${projectId}`
|
|
593
|
+
);
|
|
556
594
|
|
|
557
|
-
|
|
558
|
-
|
|
595
|
+
// --- Verification ---
|
|
596
|
+
console.log("\nVerifying configuration...");
|
|
559
597
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
598
|
+
const gcloudConfigDir =
|
|
599
|
+
process.env.CLOUDSDK_CONFIG || path.join(os.homedir(), ".config", "gcloud");
|
|
600
|
+
const activeConfigPath = path.join(gcloudConfigDir, "active_config");
|
|
563
601
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
602
|
+
let currentConfig = "unknown";
|
|
603
|
+
if (fs.existsSync(activeConfigPath)) {
|
|
604
|
+
currentConfig = fs.readFileSync(activeConfigPath, "utf8").trim();
|
|
605
|
+
} else {
|
|
606
|
+
console.warn(
|
|
607
|
+
`Warning: Could not find active_config file at ${activeConfigPath}`
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const currentProject = execSync("gcloud config get project", { shell: true })
|
|
612
|
+
.toString()
|
|
613
|
+
.trim();
|
|
614
|
+
console.log(
|
|
615
|
+
`Active config is ${currentConfig} - project is ${currentProject}`
|
|
570
616
|
);
|
|
571
617
|
}
|
|
618
|
+
let sa_email = ""
|
|
619
|
+
// -- specifc to dwd auth type
|
|
620
|
+
if (AUTH_TYPE === "dwd") {
|
|
621
|
+
console.log("Initiating keyless domain-wide delegation authentication...");
|
|
622
|
+
const current_user = execSync("gcloud config get-value account", { shell: true })
|
|
623
|
+
.toString()
|
|
624
|
+
.trim();
|
|
625
|
+
|
|
626
|
+
sa_email = `${GOOGLE_SERVICE_ACCOUNT_NAME}@${projectId}.iam.gserviceaccount.com`;
|
|
627
|
+
console.log(`Service account email: ${sa_email}`);
|
|
628
|
+
console.log(`Current user: ${current_user}`);
|
|
629
|
+
|
|
630
|
+
// Service Account Lifecycle
|
|
631
|
+
let existing_sa = false
|
|
632
|
+
try {
|
|
633
|
+
execSync(`gcloud iam service-accounts describe "${sa_email}"`, { shell: true });
|
|
634
|
+
existing_sa = true;
|
|
635
|
+
} catch (error) {
|
|
636
|
+
/* ignore */
|
|
637
|
+
}
|
|
638
|
+
if (existing_sa) {
|
|
639
|
+
const serviceAccountNameQuestion = {
|
|
640
|
+
type: "select",
|
|
641
|
+
name: "ROTATE_OR_REPLACE",
|
|
642
|
+
message: "Select an action for the existing service account",
|
|
643
|
+
initial: 0,
|
|
644
|
+
choices: [
|
|
645
|
+
{ title: "Keep/rotate existing Service Account", value: "keep" },
|
|
646
|
+
{ title: "Replace/Recreate Service Account", value: "replace" },
|
|
647
|
+
],
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
const { ROTATE_OR_REPLACE } = await prompts(serviceAccountNameQuestion);
|
|
651
|
+
if (ROTATE_OR_REPLACE === "replace") {
|
|
652
|
+
console.log("Replacing existing service account...");
|
|
653
|
+
runCommandSync(`gcloud iam service-accounts delete "${sa_email}" --quiet --format=none`);
|
|
654
|
+
runCommandSync(`gcloud iam service-accounts create "${GOOGLE_SERVICE_ACCOUNT_NAME}" --display-name "${GOOGLE_SERVICE_ACCOUNT_NAME}" --quiet --format=none`);
|
|
655
|
+
}
|
|
656
|
+
} else {
|
|
657
|
+
console.log("Creating new service account...");
|
|
658
|
+
runCommandSync(`gcloud iam service-accounts create "${GOOGLE_SERVICE_ACCOUNT_NAME}" --display-name "${GOOGLE_SERVICE_ACCOUNT_NAME}" --quiet --format=none`);
|
|
659
|
+
}
|
|
572
660
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
.
|
|
576
|
-
|
|
577
|
-
`
|
|
578
|
-
|
|
661
|
+
// set service account permissions
|
|
662
|
+
runCommandSync(`gcloud projects add-iam-policy-binding "${projectId}" --member="serviceAccount:${sa_email}" --role="roles/editor" --quiet --format=none`);
|
|
663
|
+
runCommandSync(`gcloud iam service-accounts add-iam-policy-binding "${sa_email}" --member="serviceAccount:${sa_email}" --role="roles/iam.serviceAccountTokenCreator" --quiet --format=none`);
|
|
664
|
+
runCommandSync(`gcloud iam service-accounts add-iam-policy-binding "${sa_email}" --member="user:${current_user}" --role="roles/iam.serviceAccountTokenCreator" --quiet --format=none`);
|
|
665
|
+
runCommandSync(`gcloud projects add-iam-policy-binding "${projectId}" --member="serviceAccount:${sa_email}" --role="roles/logging.logWriter" --quiet --format=none`);
|
|
666
|
+
|
|
667
|
+
}
|
|
579
668
|
|
|
580
669
|
console.log("\nFetching token information...");
|
|
581
670
|
const userToken = execSync("gcloud auth print-access-token", { shell: true })
|
|
@@ -588,6 +677,7 @@ export async function authenticateUser() {
|
|
|
588
677
|
.toString()
|
|
589
678
|
.trim();
|
|
590
679
|
|
|
680
|
+
|
|
591
681
|
console.log("\n...user token scopes");
|
|
592
682
|
runCommandSync(
|
|
593
683
|
`curl https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${userToken}`
|
|
@@ -598,6 +688,18 @@ export async function authenticateUser() {
|
|
|
598
688
|
`curl https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${appDefaultToken}`
|
|
599
689
|
);
|
|
600
690
|
console.log("\nAuthentication process finished.");
|
|
691
|
+
|
|
692
|
+
if (AUTH_TYPE === "dwd") {
|
|
693
|
+
const saUniqueId = execSync(`gcloud iam service-accounts describe "${sa_email}" --format="value(uniqueId)"`, { shell: true })
|
|
694
|
+
.toString()
|
|
695
|
+
.trim();
|
|
696
|
+
console.log("\nNow you need to ensure that workspace admin console has the scopes and client ID added to Domain-Wide Delegation");
|
|
697
|
+
console.log("Enter the following in Admin Console: https://admin.google.com/ac/owl/domainwidedelegation");
|
|
698
|
+
console.log(`
|
|
699
|
+
Client ID: ${saUniqueId}
|
|
700
|
+
Scopes: ${scopes}
|
|
701
|
+
`);
|
|
702
|
+
}
|
|
601
703
|
}
|
|
602
704
|
|
|
603
705
|
/**
|