@uipath/auth 1.1.0 → 1.195.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/dist/authContext.d.ts +17 -0
- package/dist/catch-error.d.ts +5 -0
- package/dist/clientCredentials.d.ts +9 -0
- package/dist/config.d.ts +73 -0
- package/dist/constants.d.ts +10 -0
- package/dist/envAuth.d.ts +75 -0
- package/dist/getBaseHtml.d.ts +7 -0
- package/dist/index.browser.d.ts +10 -0
- package/dist/index.browser.js +234 -99
- package/dist/index.d.ts +27 -0
- package/dist/index.js +435 -188
- package/dist/interactive.d.ts +93 -0
- package/dist/loginStatus.d.ts +73 -0
- package/dist/logout.d.ts +44 -0
- package/dist/oidc.d.ts +5 -0
- package/dist/robotClientFallback.d.ts +63 -0
- package/dist/selectTenant.d.ts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/strategies/auth-strategy.d.ts +3 -0
- package/dist/strategies/browser-strategy.d.ts +4 -0
- package/dist/strategies/node-strategy.d.ts +4 -0
- package/dist/tenantSelection.d.ts +17 -0
- package/dist/tokenExchange.d.ts +13 -0
- package/dist/tokenRefresh.d.ts +27 -0
- package/dist/types.d.ts +5 -0
- package/dist/utils/envFile.d.ts +101 -0
- package/dist/utils/jwt.d.ts +43 -0
- package/dist/utils/platform.d.ts +36 -0
- package/package.json +38 -43
package/dist/index.js
CHANGED
|
@@ -728,6 +728,7 @@ var init_open = __esm(() => {
|
|
|
728
728
|
});
|
|
729
729
|
|
|
730
730
|
// ../filesystem/src/node.ts
|
|
731
|
+
import { randomUUID } from "node:crypto";
|
|
731
732
|
import { existsSync } from "node:fs";
|
|
732
733
|
import * as fs6 from "node:fs/promises";
|
|
733
734
|
import * as os2 from "node:os";
|
|
@@ -809,6 +810,90 @@ class NodeFileSystem {
|
|
|
809
810
|
async mkdir(dirPath) {
|
|
810
811
|
await fs6.mkdir(dirPath, { recursive: true });
|
|
811
812
|
}
|
|
813
|
+
async acquireLock(lockPath) {
|
|
814
|
+
const canonicalPath = await this.canonicalizeLockTarget(lockPath);
|
|
815
|
+
const lockFile = `${canonicalPath}.lock`;
|
|
816
|
+
const ownerId = randomUUID();
|
|
817
|
+
const start = Date.now();
|
|
818
|
+
while (true) {
|
|
819
|
+
try {
|
|
820
|
+
await fs6.writeFile(lockFile, ownerId, { flag: "wx" });
|
|
821
|
+
return this.createLockRelease(lockFile, ownerId);
|
|
822
|
+
} catch (error) {
|
|
823
|
+
if (!this.hasErrnoCode(error, "EEXIST")) {
|
|
824
|
+
throw error;
|
|
825
|
+
}
|
|
826
|
+
const stats = await fs6.stat(lockFile).catch(() => null);
|
|
827
|
+
if (stats && Date.now() - stats.mtimeMs > LOCK_STALE_MS) {
|
|
828
|
+
const reclaimed = await fs6.rm(lockFile, { force: true }).then(() => true).catch(() => false);
|
|
829
|
+
if (reclaimed)
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
if (Date.now() - start > LOCK_MAX_WAIT_MS) {
|
|
833
|
+
throw new Error(`ELOCKED: timed out waiting for lock on ${canonicalPath}`);
|
|
834
|
+
}
|
|
835
|
+
await new Promise((resolve2) => setTimeout(resolve2, LOCK_RETRY_MIN_MS + Math.random() * LOCK_RETRY_JITTER_MS));
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
async canonicalizeLockTarget(lockPath) {
|
|
840
|
+
const absolute = path2.resolve(lockPath);
|
|
841
|
+
const fullReal = await fs6.realpath(absolute).catch(() => null);
|
|
842
|
+
if (fullReal)
|
|
843
|
+
return fullReal;
|
|
844
|
+
const parent = path2.dirname(absolute);
|
|
845
|
+
const base = path2.basename(absolute);
|
|
846
|
+
const canonicalParent = await fs6.realpath(parent).catch(() => parent);
|
|
847
|
+
return path2.join(canonicalParent, base);
|
|
848
|
+
}
|
|
849
|
+
createLockRelease(lockFile, ownerId) {
|
|
850
|
+
const heartbeatStart = Date.now();
|
|
851
|
+
let heartbeatTimer;
|
|
852
|
+
let stopped = false;
|
|
853
|
+
const stopHeartbeat = () => {
|
|
854
|
+
stopped = true;
|
|
855
|
+
if (heartbeatTimer)
|
|
856
|
+
clearTimeout(heartbeatTimer);
|
|
857
|
+
};
|
|
858
|
+
const scheduleNextHeartbeat = () => {
|
|
859
|
+
if (stopped)
|
|
860
|
+
return;
|
|
861
|
+
if (Date.now() - heartbeatStart >= LOCK_MAX_HOLD_MS) {
|
|
862
|
+
stopped = true;
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
heartbeatTimer = setTimeout(() => {
|
|
866
|
+
runHeartbeat();
|
|
867
|
+
}, LOCK_HEARTBEAT_MS);
|
|
868
|
+
heartbeatTimer.unref?.();
|
|
869
|
+
};
|
|
870
|
+
const runHeartbeat = async () => {
|
|
871
|
+
if (stopped)
|
|
872
|
+
return;
|
|
873
|
+
const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
|
|
874
|
+
if (stopped)
|
|
875
|
+
return;
|
|
876
|
+
if (current !== ownerId) {
|
|
877
|
+
stopped = true;
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
const now = Date.now() / 1000;
|
|
881
|
+
await fs6.utimes(lockFile, now, now).catch(() => {});
|
|
882
|
+
scheduleNextHeartbeat();
|
|
883
|
+
};
|
|
884
|
+
scheduleNextHeartbeat();
|
|
885
|
+
let released = false;
|
|
886
|
+
return async () => {
|
|
887
|
+
if (released)
|
|
888
|
+
return;
|
|
889
|
+
released = true;
|
|
890
|
+
stopHeartbeat();
|
|
891
|
+
const current = await fs6.readFile(lockFile, "utf-8").catch(() => null);
|
|
892
|
+
if (current === ownerId) {
|
|
893
|
+
await fs6.rm(lockFile, { force: true });
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
}
|
|
812
897
|
async rm(filePath) {
|
|
813
898
|
await fs6.rm(filePath, { recursive: true, force: true });
|
|
814
899
|
}
|
|
@@ -854,9 +939,13 @@ class NodeFileSystem {
|
|
|
854
939
|
}
|
|
855
940
|
}
|
|
856
941
|
isEnoent(error) {
|
|
857
|
-
return
|
|
942
|
+
return this.hasErrnoCode(error, "ENOENT");
|
|
943
|
+
}
|
|
944
|
+
hasErrnoCode(error, code) {
|
|
945
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
858
946
|
}
|
|
859
947
|
}
|
|
948
|
+
var LOCK_HEARTBEAT_MS = 5000, LOCK_STALE_MS = 15000, LOCK_MAX_WAIT_MS = 20000, LOCK_MAX_HOLD_MS = 60000, LOCK_RETRY_MIN_MS = 100, LOCK_RETRY_JITTER_MS = 200;
|
|
860
949
|
var init_node = __esm(() => {
|
|
861
950
|
init_open();
|
|
862
951
|
});
|
|
@@ -870,7 +959,7 @@ var init_src = __esm(() => {
|
|
|
870
959
|
|
|
871
960
|
// ../../node_modules/@uipath/coreipc/index.js
|
|
872
961
|
var require_coreipc = __commonJS((exports, module) => {
|
|
873
|
-
var __dirname = "/
|
|
962
|
+
var __dirname = "/home/runner/work/cli/cli/node_modules/@uipath/coreipc";
|
|
874
963
|
/*! For license information please see index.js.LICENSE.txt */
|
|
875
964
|
(function(e, t) {
|
|
876
965
|
typeof exports == "object" && typeof module == "object" ? module.exports = t() : typeof define == "function" && define.amd ? define([], t) : typeof exports == "object" ? exports.ipc = t() : e.ipc = t();
|
|
@@ -19063,81 +19152,6 @@ var require_dist = __commonJS((exports) => {
|
|
|
19063
19152
|
__exportStar(require_agent(), exports);
|
|
19064
19153
|
});
|
|
19065
19154
|
|
|
19066
|
-
// src/strategies/browser-strategy.ts
|
|
19067
|
-
var exports_browser_strategy = {};
|
|
19068
|
-
__export(exports_browser_strategy, {
|
|
19069
|
-
BrowserAuthStrategy: () => BrowserAuthStrategy
|
|
19070
|
-
});
|
|
19071
|
-
|
|
19072
|
-
class BrowserAuthStrategy {
|
|
19073
|
-
async execute(url, _redirectUri, expectedState) {
|
|
19074
|
-
const global2 = getGlobalThis();
|
|
19075
|
-
if (!global2?.window) {
|
|
19076
|
-
throw new Error("Browser environment required for authentication");
|
|
19077
|
-
}
|
|
19078
|
-
const screenWidth = global2.window.screen?.width ?? 1024;
|
|
19079
|
-
const screenHeight = global2.window.screen?.height ?? 768;
|
|
19080
|
-
const width = 600;
|
|
19081
|
-
const height = 700;
|
|
19082
|
-
const left = screenWidth / 2 - width / 2;
|
|
19083
|
-
const top = screenHeight / 2 - height / 2;
|
|
19084
|
-
if (!global2.window.open) {
|
|
19085
|
-
throw new Error("window.open is not available");
|
|
19086
|
-
}
|
|
19087
|
-
const popupResult = global2.window.open(url, "uip_auth", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes,status=yes`);
|
|
19088
|
-
const popup = popupResult;
|
|
19089
|
-
if (!popup) {
|
|
19090
|
-
throw new Error(`Authentication popup was blocked by your browser.
|
|
19091
|
-
|
|
19092
|
-
` + `To continue:
|
|
19093
|
-
` + `1. Look for a popup blocker icon in your address bar
|
|
19094
|
-
` + `2. Allow popups for this site
|
|
19095
|
-
` + `3. Try logging in again
|
|
19096
|
-
|
|
19097
|
-
` + "If using an ad blocker, you may need to temporarily disable it.");
|
|
19098
|
-
}
|
|
19099
|
-
return new Promise((resolve2, reject) => {
|
|
19100
|
-
const messageHandler = (event) => {
|
|
19101
|
-
if (event.data?.type === "UIP_AUTH_CODE" && event.data.code) {
|
|
19102
|
-
if (event.data.state !== expectedState) {
|
|
19103
|
-
cleanup();
|
|
19104
|
-
reject(new Error("OAuth state mismatch — the callback state does not match the expected value. " + "This may indicate a CSRF attack. Please try signing in again."));
|
|
19105
|
-
popup.close();
|
|
19106
|
-
return;
|
|
19107
|
-
}
|
|
19108
|
-
cleanup();
|
|
19109
|
-
resolve2(event.data.code);
|
|
19110
|
-
popup.close();
|
|
19111
|
-
} else if (event.data?.type === "UIP_AUTH_ERROR") {
|
|
19112
|
-
cleanup();
|
|
19113
|
-
const errorMsg = event.data.error || "Authentication failed";
|
|
19114
|
-
reject(new Error(`Authentication failed: ${errorMsg}
|
|
19115
|
-
|
|
19116
|
-
` + "Please check your credentials and try again. " + "If the problem persists, verify your UiPath account is active."));
|
|
19117
|
-
popup.close();
|
|
19118
|
-
}
|
|
19119
|
-
};
|
|
19120
|
-
const cleanup = () => {
|
|
19121
|
-
global2.window?.removeEventListener?.("message", messageHandler);
|
|
19122
|
-
if (timer)
|
|
19123
|
-
clearInterval(timer);
|
|
19124
|
-
};
|
|
19125
|
-
if (global2.window?.addEventListener) {
|
|
19126
|
-
global2.window.addEventListener("message", messageHandler);
|
|
19127
|
-
}
|
|
19128
|
-
const timer = setInterval(() => {
|
|
19129
|
-
if (popup.closed) {
|
|
19130
|
-
cleanup();
|
|
19131
|
-
reject(new Error(`Authentication was cancelled.
|
|
19132
|
-
|
|
19133
|
-
` + "The authentication popup was closed before completing the login process. " + "Please try again and complete the authentication flow."));
|
|
19134
|
-
}
|
|
19135
|
-
}, 1000);
|
|
19136
|
-
});
|
|
19137
|
-
}
|
|
19138
|
-
}
|
|
19139
|
-
var init_browser_strategy = () => {};
|
|
19140
|
-
|
|
19141
19155
|
// src/getBaseHtml.ts
|
|
19142
19156
|
var getBaseHtml = ({ title, message, type }) => {
|
|
19143
19157
|
const icon = type === "success" ? "✓" : "✕";
|
|
@@ -19284,7 +19298,7 @@ var getBaseHtml = ({ title, message, type }) => {
|
|
|
19284
19298
|
};
|
|
19285
19299
|
|
|
19286
19300
|
// src/server.ts
|
|
19287
|
-
var startServer = async ({
|
|
19301
|
+
var AUTH_TIMEOUT_ERROR_CODE = "EAUTHTIMEOUT", startServer = async ({
|
|
19288
19302
|
redirectUri,
|
|
19289
19303
|
timeoutMs = DEFAULT_AUTH_TIMEOUT_MS,
|
|
19290
19304
|
onListening
|
|
@@ -19355,7 +19369,18 @@ var startServer = async ({
|
|
|
19355
19369
|
reject(new Error("No authorization code received"));
|
|
19356
19370
|
return;
|
|
19357
19371
|
});
|
|
19358
|
-
|
|
19372
|
+
const timeoutHandle = setTimeout(() => {
|
|
19373
|
+
server.close();
|
|
19374
|
+
const err = new Error("Authentication timeout");
|
|
19375
|
+
err.code = AUTH_TIMEOUT_ERROR_CODE;
|
|
19376
|
+
reject(err);
|
|
19377
|
+
}, timeoutMs);
|
|
19378
|
+
const bindHost = redirectUri.hostname === "localhost" ? "127.0.0.1" : redirectUri.hostname;
|
|
19379
|
+
server.on("error", (err) => {
|
|
19380
|
+
clearTimeout(timeoutHandle);
|
|
19381
|
+
reject(err);
|
|
19382
|
+
});
|
|
19383
|
+
server.listen(Number(redirectUri.port), bindHost, () => {
|
|
19359
19384
|
if (onListening) {
|
|
19360
19385
|
Promise.resolve(onListening()).catch((err) => {
|
|
19361
19386
|
server.close();
|
|
@@ -19364,10 +19389,6 @@ var startServer = async ({
|
|
|
19364
19389
|
});
|
|
19365
19390
|
}
|
|
19366
19391
|
});
|
|
19367
|
-
const timeoutHandle = setTimeout(() => {
|
|
19368
|
-
server.close();
|
|
19369
|
-
reject(new Error("Authentication timeout"));
|
|
19370
|
-
}, timeoutMs);
|
|
19371
19392
|
server.on("close", () => {
|
|
19372
19393
|
clearTimeout(timeoutHandle);
|
|
19373
19394
|
});
|
|
@@ -19377,6 +19398,81 @@ var init_server = __esm(() => {
|
|
|
19377
19398
|
init_constants();
|
|
19378
19399
|
});
|
|
19379
19400
|
|
|
19401
|
+
// src/strategies/browser-strategy.ts
|
|
19402
|
+
var exports_browser_strategy = {};
|
|
19403
|
+
__export(exports_browser_strategy, {
|
|
19404
|
+
BrowserAuthStrategy: () => BrowserAuthStrategy
|
|
19405
|
+
});
|
|
19406
|
+
|
|
19407
|
+
class BrowserAuthStrategy {
|
|
19408
|
+
async execute(url, _redirectUri, expectedState) {
|
|
19409
|
+
const global2 = getGlobalThis();
|
|
19410
|
+
if (!global2?.window) {
|
|
19411
|
+
throw new Error("Browser environment required for authentication");
|
|
19412
|
+
}
|
|
19413
|
+
const screenWidth = global2.window.screen?.width ?? 1024;
|
|
19414
|
+
const screenHeight = global2.window.screen?.height ?? 768;
|
|
19415
|
+
const width = 600;
|
|
19416
|
+
const height = 700;
|
|
19417
|
+
const left = screenWidth / 2 - width / 2;
|
|
19418
|
+
const top = screenHeight / 2 - height / 2;
|
|
19419
|
+
if (!global2.window.open) {
|
|
19420
|
+
throw new Error("window.open is not available");
|
|
19421
|
+
}
|
|
19422
|
+
const popupResult = global2.window.open(url, "uip_auth", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes,status=yes`);
|
|
19423
|
+
const popup = popupResult;
|
|
19424
|
+
if (!popup) {
|
|
19425
|
+
throw new Error(`Authentication popup was blocked by your browser.
|
|
19426
|
+
|
|
19427
|
+
` + `To continue:
|
|
19428
|
+
` + `1. Look for a popup blocker icon in your address bar
|
|
19429
|
+
` + `2. Allow popups for this site
|
|
19430
|
+
` + `3. Try logging in again
|
|
19431
|
+
|
|
19432
|
+
` + "If using an ad blocker, you may need to temporarily disable it.");
|
|
19433
|
+
}
|
|
19434
|
+
return new Promise((resolve2, reject) => {
|
|
19435
|
+
const messageHandler = (event) => {
|
|
19436
|
+
if (event.data?.type === "UIP_AUTH_CODE" && event.data.code) {
|
|
19437
|
+
if (event.data.state !== expectedState) {
|
|
19438
|
+
cleanup();
|
|
19439
|
+
reject(new Error("OAuth state mismatch — the callback state does not match the expected value. " + "This may indicate a CSRF attack. Please try signing in again."));
|
|
19440
|
+
popup.close();
|
|
19441
|
+
return;
|
|
19442
|
+
}
|
|
19443
|
+
cleanup();
|
|
19444
|
+
resolve2(event.data.code);
|
|
19445
|
+
popup.close();
|
|
19446
|
+
} else if (event.data?.type === "UIP_AUTH_ERROR") {
|
|
19447
|
+
cleanup();
|
|
19448
|
+
const errorMsg = event.data.error || "Authentication failed";
|
|
19449
|
+
reject(new Error(`Authentication failed: ${errorMsg}
|
|
19450
|
+
|
|
19451
|
+
` + "Please check your credentials and try again. " + "If the problem persists, verify your UiPath account is active."));
|
|
19452
|
+
popup.close();
|
|
19453
|
+
}
|
|
19454
|
+
};
|
|
19455
|
+
const cleanup = () => {
|
|
19456
|
+
global2.window?.removeEventListener?.("message", messageHandler);
|
|
19457
|
+
if (timer)
|
|
19458
|
+
clearInterval(timer);
|
|
19459
|
+
};
|
|
19460
|
+
if (global2.window?.addEventListener) {
|
|
19461
|
+
global2.window.addEventListener("message", messageHandler);
|
|
19462
|
+
}
|
|
19463
|
+
const timer = setInterval(() => {
|
|
19464
|
+
if (popup.closed) {
|
|
19465
|
+
cleanup();
|
|
19466
|
+
reject(new Error(`Authentication was cancelled.
|
|
19467
|
+
|
|
19468
|
+
` + "The authentication popup was closed before completing the login process. " + "Please try again and complete the authentication flow."));
|
|
19469
|
+
}
|
|
19470
|
+
}, 1000);
|
|
19471
|
+
});
|
|
19472
|
+
}
|
|
19473
|
+
}
|
|
19474
|
+
var init_browser_strategy = () => {};
|
|
19475
|
+
|
|
19380
19476
|
// src/strategies/node-strategy.ts
|
|
19381
19477
|
var exports_node_strategy = {};
|
|
19382
19478
|
__export(exports_node_strategy, {
|
|
@@ -19455,32 +19551,7 @@ class InvalidBaseUrlError extends Error {
|
|
|
19455
19551
|
this.name = "InvalidBaseUrlError";
|
|
19456
19552
|
}
|
|
19457
19553
|
}
|
|
19458
|
-
var DEFAULT_SCOPES = [
|
|
19459
|
-
"offline_access",
|
|
19460
|
-
"ProcessMining",
|
|
19461
|
-
"OrchestratorApiUserAccess",
|
|
19462
|
-
"StudioWebBackend",
|
|
19463
|
-
"IdentityServerApi",
|
|
19464
|
-
"ConnectionService",
|
|
19465
|
-
"DataService",
|
|
19466
|
-
"DataServiceApiUserAccess",
|
|
19467
|
-
"DocumentUnderstanding",
|
|
19468
|
-
"EnterpriseContextService",
|
|
19469
|
-
"Directory",
|
|
19470
|
-
"JamJamApi",
|
|
19471
|
-
"LLMGateway",
|
|
19472
|
-
"LLMOps",
|
|
19473
|
-
"OMS",
|
|
19474
|
-
"RCS.FolderAuthorization",
|
|
19475
|
-
"RCS.TagsManagement",
|
|
19476
|
-
"TestmanagerApiUserAccess",
|
|
19477
|
-
"AutomationSolutions",
|
|
19478
|
-
"StudioWebTypeCacheService",
|
|
19479
|
-
"Docs.GPT.Search",
|
|
19480
|
-
"Insights",
|
|
19481
|
-
"ReferenceToken",
|
|
19482
|
-
"Audit.Read"
|
|
19483
|
-
];
|
|
19554
|
+
var DEFAULT_SCOPES = ["openid", "profile", "offline_access"];
|
|
19484
19555
|
var normalizeAndValidateBaseUrl = (rawUrl) => {
|
|
19485
19556
|
let baseUrl = rawUrl;
|
|
19486
19557
|
if (baseUrl.endsWith("/identity_/")) {
|
|
@@ -19530,7 +19601,8 @@ var resolveConfigAsync = async ({
|
|
|
19530
19601
|
if (!clientSecret && fileAuth.clientSecret) {
|
|
19531
19602
|
clientSecret = fileAuth.clientSecret;
|
|
19532
19603
|
}
|
|
19533
|
-
const
|
|
19604
|
+
const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && Boolean(clientSecret);
|
|
19605
|
+
const scopes = customScopes && customScopes.length > 0 ? customScopes : fileAuth.scopes && fileAuth.scopes.length > 0 ? fileAuth.scopes : isExternalAppAuth ? [] : DEFAULT_SCOPES;
|
|
19534
19606
|
return {
|
|
19535
19607
|
clientId,
|
|
19536
19608
|
clientSecret,
|
|
@@ -20668,6 +20740,129 @@ function normalizeTokenRefreshFailure() {
|
|
|
20668
20740
|
function normalizeTokenRefreshUnavailableFailure() {
|
|
20669
20741
|
return "token refresh failed before authentication completed";
|
|
20670
20742
|
}
|
|
20743
|
+
function errorMessage(error) {
|
|
20744
|
+
return error instanceof Error ? error.message : String(error);
|
|
20745
|
+
}
|
|
20746
|
+
function computeExpirationThreshold(ensureTokenValidityMinutes) {
|
|
20747
|
+
return new Date(Date.now() + (ensureTokenValidityMinutes ?? 0) * 60 * 1000);
|
|
20748
|
+
}
|
|
20749
|
+
async function runRefreshLocked(inputs) {
|
|
20750
|
+
const {
|
|
20751
|
+
absolutePath,
|
|
20752
|
+
refreshToken: callerRefreshToken,
|
|
20753
|
+
customAuthority,
|
|
20754
|
+
ensureTokenValidityMinutes,
|
|
20755
|
+
loadEnvFile,
|
|
20756
|
+
saveEnvFile,
|
|
20757
|
+
refreshFn,
|
|
20758
|
+
resolveConfig
|
|
20759
|
+
} = inputs;
|
|
20760
|
+
const expirationThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
|
|
20761
|
+
let fresh;
|
|
20762
|
+
try {
|
|
20763
|
+
fresh = await loadEnvFile({ envPath: absolutePath });
|
|
20764
|
+
} catch (error) {
|
|
20765
|
+
return {
|
|
20766
|
+
kind: "fail",
|
|
20767
|
+
status: {
|
|
20768
|
+
loginStatus: "Refresh Failed",
|
|
20769
|
+
hint: "Could not read the auth file while refreshing. Retry, or run 'uip login' to re-authenticate.",
|
|
20770
|
+
tokenRefresh: {
|
|
20771
|
+
attempted: false,
|
|
20772
|
+
success: false,
|
|
20773
|
+
errorMessage: `auth file read failed: ${errorMessage(error)}`
|
|
20774
|
+
}
|
|
20775
|
+
}
|
|
20776
|
+
};
|
|
20777
|
+
}
|
|
20778
|
+
const freshAccess = fresh.UIPATH_ACCESS_TOKEN;
|
|
20779
|
+
const freshExp = freshAccess ? getTokenExpiration(freshAccess) : undefined;
|
|
20780
|
+
if (freshAccess && freshExp && freshExp > expirationThreshold) {
|
|
20781
|
+
return {
|
|
20782
|
+
kind: "ok",
|
|
20783
|
+
accessToken: freshAccess,
|
|
20784
|
+
refreshToken: fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken,
|
|
20785
|
+
expiration: freshExp,
|
|
20786
|
+
tokenRefresh: { attempted: false, success: true }
|
|
20787
|
+
};
|
|
20788
|
+
}
|
|
20789
|
+
const tokenForIdP = fresh.UIPATH_REFRESH_TOKEN ?? callerRefreshToken;
|
|
20790
|
+
let refreshedAccess;
|
|
20791
|
+
let refreshedRefresh;
|
|
20792
|
+
try {
|
|
20793
|
+
const config = await resolveConfig({ customAuthority });
|
|
20794
|
+
const refreshed = await refreshFn({
|
|
20795
|
+
refreshToken: tokenForIdP,
|
|
20796
|
+
tokenEndpoint: config.tokenEndpoint,
|
|
20797
|
+
clientId: config.clientId,
|
|
20798
|
+
expectedAuthority: customAuthority
|
|
20799
|
+
});
|
|
20800
|
+
refreshedAccess = refreshed.accessToken;
|
|
20801
|
+
refreshedRefresh = refreshed.refreshToken;
|
|
20802
|
+
} catch (error) {
|
|
20803
|
+
const isOAuthFailure = isTokenRefreshOAuthFailure(error);
|
|
20804
|
+
const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
|
|
20805
|
+
const message = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
|
|
20806
|
+
return {
|
|
20807
|
+
kind: "fail",
|
|
20808
|
+
status: {
|
|
20809
|
+
loginStatus: "Refresh Failed",
|
|
20810
|
+
hint,
|
|
20811
|
+
tokenRefresh: {
|
|
20812
|
+
attempted: true,
|
|
20813
|
+
success: false,
|
|
20814
|
+
errorMessage: message
|
|
20815
|
+
}
|
|
20816
|
+
}
|
|
20817
|
+
};
|
|
20818
|
+
}
|
|
20819
|
+
const refreshedExp = getTokenExpiration(refreshedAccess);
|
|
20820
|
+
if (!refreshedExp || refreshedExp <= new Date) {
|
|
20821
|
+
return {
|
|
20822
|
+
kind: "fail",
|
|
20823
|
+
status: {
|
|
20824
|
+
loginStatus: "Refresh Failed",
|
|
20825
|
+
hint: "The identity server returned an unusable token. Run 'uip login' to re-authenticate.",
|
|
20826
|
+
tokenRefresh: {
|
|
20827
|
+
attempted: true,
|
|
20828
|
+
success: false,
|
|
20829
|
+
errorMessage: "refreshed token has no valid expiration claim"
|
|
20830
|
+
}
|
|
20831
|
+
}
|
|
20832
|
+
};
|
|
20833
|
+
}
|
|
20834
|
+
try {
|
|
20835
|
+
await saveEnvFile({
|
|
20836
|
+
envPath: absolutePath,
|
|
20837
|
+
data: {
|
|
20838
|
+
UIPATH_ACCESS_TOKEN: refreshedAccess,
|
|
20839
|
+
UIPATH_REFRESH_TOKEN: refreshedRefresh
|
|
20840
|
+
},
|
|
20841
|
+
merge: true
|
|
20842
|
+
});
|
|
20843
|
+
return {
|
|
20844
|
+
kind: "ok",
|
|
20845
|
+
accessToken: refreshedAccess,
|
|
20846
|
+
refreshToken: refreshedRefresh,
|
|
20847
|
+
expiration: refreshedExp,
|
|
20848
|
+
tokenRefresh: { attempted: true, success: true }
|
|
20849
|
+
};
|
|
20850
|
+
} catch (error) {
|
|
20851
|
+
const msg = errorMessage(error);
|
|
20852
|
+
return {
|
|
20853
|
+
kind: "ok",
|
|
20854
|
+
accessToken: refreshedAccess,
|
|
20855
|
+
refreshToken: refreshedRefresh,
|
|
20856
|
+
expiration: refreshedExp,
|
|
20857
|
+
persistenceWarning: `Access token refreshed in memory but could not be written to ${absolutePath}: ${msg}. The next CLI invocation will fail until the file can be updated — run 'uip login' to re-authenticate.`,
|
|
20858
|
+
tokenRefresh: {
|
|
20859
|
+
attempted: true,
|
|
20860
|
+
success: true,
|
|
20861
|
+
errorMessage: `persistence failed: ${msg}`
|
|
20862
|
+
}
|
|
20863
|
+
};
|
|
20864
|
+
}
|
|
20865
|
+
}
|
|
20671
20866
|
var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
20672
20867
|
const {
|
|
20673
20868
|
resolveEnvFilePath = resolveEnvFilePathAsync,
|
|
@@ -20742,73 +20937,103 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
20742
20937
|
let refreshToken = credentials.UIPATH_REFRESH_TOKEN;
|
|
20743
20938
|
let expiration = getTokenExpiration(accessToken);
|
|
20744
20939
|
let persistenceWarning;
|
|
20940
|
+
let lockReleaseFailed = false;
|
|
20745
20941
|
let tokenRefresh;
|
|
20746
|
-
const
|
|
20747
|
-
|
|
20748
|
-
|
|
20749
|
-
|
|
20942
|
+
const outerThreshold = computeExpirationThreshold(ensureTokenValidityMinutes);
|
|
20943
|
+
const tryGlobalCredsHint = async () => {
|
|
20944
|
+
const fs7 = getFs();
|
|
20945
|
+
const globalPath = fs7.path.join(fs7.env.homedir(), envFilePath);
|
|
20946
|
+
if (absolutePath === globalPath)
|
|
20947
|
+
return;
|
|
20948
|
+
if (!await fs7.exists(globalPath))
|
|
20949
|
+
return;
|
|
20750
20950
|
try {
|
|
20751
|
-
const
|
|
20752
|
-
|
|
20753
|
-
|
|
20754
|
-
const
|
|
20755
|
-
|
|
20756
|
-
|
|
20757
|
-
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
refreshedAccess = refreshed.accessToken;
|
|
20761
|
-
refreshedRefresh = refreshed.refreshToken;
|
|
20762
|
-
} catch (error) {
|
|
20763
|
-
const isOAuthFailure = isTokenRefreshOAuthFailure(error);
|
|
20764
|
-
const hint = isOAuthFailure ? "Run 'uip login' to re-authenticate — the stored refresh token is invalid or expired." : "Token refresh failed. Check your network connection, then retry or run 'uip login' to re-authenticate.";
|
|
20765
|
-
const errorMessage = isOAuthFailure ? normalizeTokenRefreshFailure() : normalizeTokenRefreshUnavailableFailure();
|
|
20766
|
-
return {
|
|
20767
|
-
loginStatus: "Refresh Failed",
|
|
20768
|
-
hint,
|
|
20769
|
-
tokenRefresh: {
|
|
20770
|
-
attempted: true,
|
|
20771
|
-
success: false,
|
|
20772
|
-
errorMessage
|
|
20773
|
-
}
|
|
20774
|
-
};
|
|
20951
|
+
const globalCreds = await loadEnvFile({ envPath: globalPath });
|
|
20952
|
+
if (!globalCreds.UIPATH_ACCESS_TOKEN)
|
|
20953
|
+
return;
|
|
20954
|
+
const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
|
|
20955
|
+
if (globalExp && globalExp <= new Date)
|
|
20956
|
+
return;
|
|
20957
|
+
return `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
|
|
20958
|
+
} catch {
|
|
20959
|
+
return;
|
|
20775
20960
|
}
|
|
20776
|
-
|
|
20777
|
-
|
|
20961
|
+
};
|
|
20962
|
+
if (expiration && expiration <= outerThreshold && refreshToken) {
|
|
20963
|
+
let release;
|
|
20964
|
+
try {
|
|
20965
|
+
release = await getFs().acquireLock(absolutePath);
|
|
20966
|
+
} catch (error) {
|
|
20967
|
+
const msg = errorMessage(error);
|
|
20968
|
+
const globalHint = await tryGlobalCredsHint();
|
|
20969
|
+
if (globalHint) {
|
|
20970
|
+
return {
|
|
20971
|
+
loginStatus: "Expired",
|
|
20972
|
+
accessToken,
|
|
20973
|
+
refreshToken,
|
|
20974
|
+
baseUrl: credentials.UIPATH_URL,
|
|
20975
|
+
organizationName: credentials.UIPATH_ORGANIZATION_NAME,
|
|
20976
|
+
organizationId: credentials.UIPATH_ORGANIZATION_ID,
|
|
20977
|
+
tenantName: credentials.UIPATH_TENANT_NAME,
|
|
20978
|
+
tenantId: credentials.UIPATH_TENANT_ID,
|
|
20979
|
+
expiration,
|
|
20980
|
+
source: "file" /* File */,
|
|
20981
|
+
hint: globalHint,
|
|
20982
|
+
tokenRefresh: {
|
|
20983
|
+
attempted: false,
|
|
20984
|
+
success: false,
|
|
20985
|
+
errorMessage: `lock acquisition failed: ${msg}`
|
|
20986
|
+
}
|
|
20987
|
+
};
|
|
20988
|
+
}
|
|
20778
20989
|
return {
|
|
20779
20990
|
loginStatus: "Refresh Failed",
|
|
20780
|
-
hint: "
|
|
20991
|
+
hint: "Could not acquire the auth-file lock — too many concurrent `uip` processes, or a permission issue on the auth directory. Retry, or run 'uip login' to re-authenticate.",
|
|
20781
20992
|
tokenRefresh: {
|
|
20782
|
-
attempted:
|
|
20993
|
+
attempted: false,
|
|
20783
20994
|
success: false,
|
|
20784
|
-
errorMessage:
|
|
20995
|
+
errorMessage: `lock acquisition failed: ${msg}`
|
|
20785
20996
|
}
|
|
20786
20997
|
};
|
|
20787
20998
|
}
|
|
20788
|
-
|
|
20789
|
-
refreshToken = refreshedRefresh;
|
|
20790
|
-
expiration = refreshedExp;
|
|
20999
|
+
let lockedFailure;
|
|
20791
21000
|
try {
|
|
20792
|
-
await
|
|
20793
|
-
|
|
20794
|
-
|
|
20795
|
-
|
|
20796
|
-
|
|
20797
|
-
|
|
20798
|
-
|
|
21001
|
+
const outcome = await runRefreshLocked({
|
|
21002
|
+
absolutePath,
|
|
21003
|
+
refreshToken,
|
|
21004
|
+
customAuthority: credentials.UIPATH_URL,
|
|
21005
|
+
ensureTokenValidityMinutes,
|
|
21006
|
+
loadEnvFile,
|
|
21007
|
+
saveEnvFile,
|
|
21008
|
+
refreshFn: refreshTokenFn,
|
|
21009
|
+
resolveConfig
|
|
20799
21010
|
});
|
|
20800
|
-
|
|
20801
|
-
|
|
20802
|
-
|
|
20803
|
-
|
|
20804
|
-
|
|
20805
|
-
|
|
20806
|
-
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
21011
|
+
if (outcome.kind === "fail") {
|
|
21012
|
+
lockedFailure = outcome.status;
|
|
21013
|
+
} else {
|
|
21014
|
+
accessToken = outcome.accessToken;
|
|
21015
|
+
refreshToken = outcome.refreshToken;
|
|
21016
|
+
expiration = outcome.expiration;
|
|
21017
|
+
tokenRefresh = outcome.tokenRefresh;
|
|
21018
|
+
if (outcome.persistenceWarning) {
|
|
21019
|
+
persistenceWarning = outcome.persistenceWarning;
|
|
21020
|
+
}
|
|
21021
|
+
}
|
|
21022
|
+
} finally {
|
|
21023
|
+
try {
|
|
21024
|
+
await release();
|
|
21025
|
+
} catch {
|
|
21026
|
+
lockReleaseFailed = true;
|
|
21027
|
+
}
|
|
21028
|
+
}
|
|
21029
|
+
if (lockedFailure) {
|
|
21030
|
+
const globalHint = await tryGlobalCredsHint();
|
|
21031
|
+
const base = globalHint ? {
|
|
21032
|
+
...lockedFailure,
|
|
21033
|
+
loginStatus: "Expired",
|
|
21034
|
+
hint: globalHint
|
|
21035
|
+
} : lockedFailure;
|
|
21036
|
+
return lockReleaseFailed ? { ...base, lockReleaseFailed: true } : base;
|
|
20812
21037
|
}
|
|
20813
21038
|
}
|
|
20814
21039
|
const result = {
|
|
@@ -20823,23 +21048,13 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
|
|
|
20823
21048
|
expiration,
|
|
20824
21049
|
source: "file" /* File */,
|
|
20825
21050
|
...persistenceWarning ? { hint: persistenceWarning, persistenceFailed: true } : {},
|
|
21051
|
+
...lockReleaseFailed ? { lockReleaseFailed: true } : {},
|
|
20826
21052
|
...tokenRefresh ? { tokenRefresh } : {}
|
|
20827
21053
|
};
|
|
20828
21054
|
if (result.loginStatus === "Expired") {
|
|
20829
|
-
const
|
|
20830
|
-
|
|
20831
|
-
|
|
20832
|
-
try {
|
|
20833
|
-
const globalCreds = await loadEnvFile({
|
|
20834
|
-
envPath: globalPath
|
|
20835
|
-
});
|
|
20836
|
-
if (globalCreds.UIPATH_ACCESS_TOKEN) {
|
|
20837
|
-
const globalExp = getTokenExpiration(globalCreds.UIPATH_ACCESS_TOKEN);
|
|
20838
|
-
if (!globalExp || globalExp > new Date) {
|
|
20839
|
-
result.hint = `Local credentials file at ${absolutePath} has expired credentials. Valid credentials exist in ${globalPath}. Remove the local file or run 'uip login' to re-authenticate.`;
|
|
20840
|
-
}
|
|
20841
|
-
}
|
|
20842
|
-
} catch {}
|
|
21055
|
+
const globalHint = await tryGlobalCredsHint();
|
|
21056
|
+
if (globalHint) {
|
|
21057
|
+
result.hint = globalHint;
|
|
20843
21058
|
}
|
|
20844
21059
|
}
|
|
20845
21060
|
return result;
|
|
@@ -20899,9 +21114,11 @@ var clientCredentialsLogin = async ({
|
|
|
20899
21114
|
const params = {
|
|
20900
21115
|
grant_type: "client_credentials",
|
|
20901
21116
|
client_id: config.clientId,
|
|
20902
|
-
client_secret: config.clientSecret ?? ""
|
|
20903
|
-
scope: config.scopes.join(" ")
|
|
21117
|
+
client_secret: config.clientSecret ?? ""
|
|
20904
21118
|
};
|
|
21119
|
+
if (config.scopes.length > 0) {
|
|
21120
|
+
params.scope = config.scopes.join(" ");
|
|
21121
|
+
}
|
|
20905
21122
|
const tokenResponse = await fetch(config.tokenEndpoint, {
|
|
20906
21123
|
method: "POST",
|
|
20907
21124
|
headers: {
|
|
@@ -21109,11 +21326,25 @@ var interactiveLoginWithDeps = async (options, deps) => {
|
|
|
21109
21326
|
searchDir = parentDir;
|
|
21110
21327
|
}
|
|
21111
21328
|
}
|
|
21112
|
-
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21329
|
+
let saveRelease;
|
|
21330
|
+
try {
|
|
21331
|
+
if (typeof fs7.acquireLock === "function") {
|
|
21332
|
+
saveRelease = await fs7.acquireLock(savePath);
|
|
21333
|
+
}
|
|
21334
|
+
} catch {
|
|
21335
|
+
saveRelease = undefined;
|
|
21336
|
+
}
|
|
21337
|
+
try {
|
|
21338
|
+
await saveEnvFile({
|
|
21339
|
+
envPath: savePath,
|
|
21340
|
+
data: credentials,
|
|
21341
|
+
merge: true
|
|
21342
|
+
});
|
|
21343
|
+
} finally {
|
|
21344
|
+
if (saveRelease) {
|
|
21345
|
+
await saveRelease().catch(() => {});
|
|
21346
|
+
}
|
|
21347
|
+
}
|
|
21117
21348
|
const reportedPath = fs7.path.isAbsolute(savePath) ? savePath : fs7.path.join(fs7.env.homedir(), savePath);
|
|
21118
21349
|
emit({
|
|
21119
21350
|
type: "saved",
|
|
@@ -21135,7 +21366,21 @@ async function logoutWithDeps(options, deps = {}) {
|
|
|
21135
21366
|
const fs7 = getFs();
|
|
21136
21367
|
const { absolutePath } = await resolveEnvFilePath(options.file);
|
|
21137
21368
|
if (absolutePath && await fs7.exists(absolutePath)) {
|
|
21138
|
-
|
|
21369
|
+
let release;
|
|
21370
|
+
try {
|
|
21371
|
+
if (typeof fs7.acquireLock === "function") {
|
|
21372
|
+
release = await fs7.acquireLock(absolutePath);
|
|
21373
|
+
}
|
|
21374
|
+
} catch {
|
|
21375
|
+
release = undefined;
|
|
21376
|
+
}
|
|
21377
|
+
try {
|
|
21378
|
+
await fs7.rm(absolutePath);
|
|
21379
|
+
} finally {
|
|
21380
|
+
if (release) {
|
|
21381
|
+
await release().catch(() => {});
|
|
21382
|
+
}
|
|
21383
|
+
}
|
|
21139
21384
|
return {
|
|
21140
21385
|
success: true,
|
|
21141
21386
|
message: `Logged out successfully. Removed ${absolutePath}`,
|
|
@@ -21153,6 +21398,7 @@ async function logout(options) {
|
|
|
21153
21398
|
}
|
|
21154
21399
|
|
|
21155
21400
|
// src/index.ts
|
|
21401
|
+
init_server();
|
|
21156
21402
|
var authenticate = async ({
|
|
21157
21403
|
baseUrl,
|
|
21158
21404
|
clientId,
|
|
@@ -21252,5 +21498,6 @@ export {
|
|
|
21252
21498
|
ENV_AUTH_ENABLE_VAR,
|
|
21253
21499
|
ENFORCE_ROBOT_AUTH_VAR,
|
|
21254
21500
|
DEFAULT_ENV_FILENAME,
|
|
21255
|
-
DEFAULT_AUTH_FILENAME
|
|
21501
|
+
DEFAULT_AUTH_FILENAME,
|
|
21502
|
+
AUTH_TIMEOUT_ERROR_CODE
|
|
21256
21503
|
};
|