@sitecore-content-sdk/cli 0.2.0-beta.13 → 0.2.0-beta.15
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/cjs/scripts/auth/list.js +8 -3
- package/dist/cjs/scripts/auth/login.js +19 -11
- package/dist/cjs/scripts/auth/logout.js +12 -6
- package/dist/cjs/scripts/auth/status.js +10 -5
- package/dist/esm/scripts/auth/list.js +5 -1
- package/dist/esm/scripts/auth/login.js +13 -6
- package/dist/esm/scripts/auth/logout.js +7 -2
- package/dist/esm/scripts/auth/status.js +6 -2
- package/package.json +3 -3
- package/types/scripts/auth/list.d.ts +1 -0
- package/types/scripts/auth/login.d.ts +2 -1
- package/types/scripts/auth/logout.d.ts +1 -0
- package/types/scripts/auth/status.d.ts +1 -0
- package/dist/cjs/scripts/auth/models.js +0 -2
- package/dist/cjs/utils/auth/flow.js +0 -72
- package/dist/cjs/utils/auth/renewal.js +0 -95
- package/dist/cjs/utils/auth/tenant-state.js +0 -91
- package/dist/cjs/utils/auth/tenant-store.js +0 -212
- package/dist/esm/scripts/auth/models.js +0 -1
- package/dist/esm/utils/auth/flow.js +0 -68
- package/dist/esm/utils/auth/renewal.js +0 -90
- package/dist/esm/utils/auth/tenant-state.js +0 -53
- package/dist/esm/utils/auth/tenant-store.js +0 -170
- package/types/scripts/auth/models.d.ts +0 -94
- package/types/utils/auth/flow.d.ts +0 -24
- package/types/utils/auth/renewal.d.ts +0 -22
- package/types/utils/auth/tenant-state.d.ts +0 -14
- package/types/utils/auth/tenant-store.d.ts +0 -40
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.writeTenantAuthInfo = writeTenantAuthInfo;
|
|
46
|
-
exports.readTenantAuthInfo = readTenantAuthInfo;
|
|
47
|
-
exports.writeTenantInfo = writeTenantInfo;
|
|
48
|
-
exports.readTenantInfo = readTenantInfo;
|
|
49
|
-
exports.deleteTenantAuthInfo = deleteTenantAuthInfo;
|
|
50
|
-
exports.getAllTenantsInfo = getAllTenantsInfo;
|
|
51
|
-
exports.decodeJwtPayload = decodeJwtPayload;
|
|
52
|
-
const fs = __importStar(require("fs"));
|
|
53
|
-
const path = __importStar(require("path"));
|
|
54
|
-
const os = __importStar(require("os"));
|
|
55
|
-
const CLAIMS = 'https://auth.sitecorecloud.io/claims';
|
|
56
|
-
const rootDir = path.join(os.homedir(), '.sitecore', 'sitecore-tools');
|
|
57
|
-
/**
|
|
58
|
-
* Get the full path to the tenant-specific folder.
|
|
59
|
-
* @param {string} tenantId - The tenant ID.
|
|
60
|
-
* @returns The absolute path to the tenant directory.
|
|
61
|
-
*/
|
|
62
|
-
function getTenantPath(tenantId) {
|
|
63
|
-
return path.join(rootDir, tenantId);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Write the authentication configuration for a tenant.
|
|
67
|
-
* @param {string} tenantId - The tenant ID.
|
|
68
|
-
* @param {TenantAuth} authInfo - The tenant's auth data.
|
|
69
|
-
*/
|
|
70
|
-
function writeTenantAuthInfo(tenantId, authInfo) {
|
|
71
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
-
try {
|
|
73
|
-
const dir = getTenantPath(tenantId);
|
|
74
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
75
|
-
fs.writeFileSync(path.join(dir, 'auth.json'), JSON.stringify(authInfo, null, 2));
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
console.error(`\n Failed to write auth.json for tenant '${tenantId}': ${error.message}`);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Read the authentication configuration for a tenant.
|
|
84
|
-
* @param {string} tenantId - The tenant ID.
|
|
85
|
-
* @returns Parsed auth config or null if not found or failed to read.
|
|
86
|
-
*/
|
|
87
|
-
function readTenantAuthInfo(tenantId) {
|
|
88
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
-
const filePath = path.join(getTenantPath(tenantId), 'auth.json');
|
|
90
|
-
if (!fs.existsSync(filePath))
|
|
91
|
-
return null;
|
|
92
|
-
try {
|
|
93
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
94
|
-
return JSON.parse(raw);
|
|
95
|
-
}
|
|
96
|
-
catch (error) {
|
|
97
|
-
console.error(`\n Failed to read auth.json for tenant '${tenantId}': ${error.message}`);
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Write the public metadata information for a tenant.
|
|
104
|
-
* @param {TenantInfo} info - The tenant info object.
|
|
105
|
-
*/
|
|
106
|
-
function writeTenantInfo(info) {
|
|
107
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
-
try {
|
|
109
|
-
const dir = getTenantPath(info.tenantId);
|
|
110
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
111
|
-
fs.writeFileSync(path.join(dir, 'info.json'), JSON.stringify(info, null, 2));
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
console.error(`\n Failed to write info.json for tenant '${info.tenantId}': ${error.message}`);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Read the public metadata information for a tenant.
|
|
120
|
-
* @param {string} tenantId - The tenant ID.
|
|
121
|
-
* @returns Parsed tenant info or null if not found or failed to read.
|
|
122
|
-
*/
|
|
123
|
-
function readTenantInfo(tenantId) {
|
|
124
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
-
const infoFilePath = path.join(getTenantPath(tenantId), 'info.json');
|
|
126
|
-
if (!fs.existsSync(infoFilePath)) {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
try {
|
|
130
|
-
const content = fs.readFileSync(infoFilePath, 'utf-8');
|
|
131
|
-
return JSON.parse(content);
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
console.error(`\n Failed to read info.json for tenant '${tenantId}': ${error.message}`);
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Deletes the stored auth.json file for the given tenant.
|
|
141
|
-
* @param {string} tenantId - The tenant ID.
|
|
142
|
-
*/
|
|
143
|
-
function deleteTenantAuthInfo(tenantId) {
|
|
144
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
-
const filePath = path.join(getTenantPath(tenantId), 'auth.json');
|
|
146
|
-
try {
|
|
147
|
-
if (fs.existsSync(filePath)) {
|
|
148
|
-
fs.unlinkSync(filePath);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
console.error(`\n Failed to delete auth.json for tenant '${tenantId}': ${error.message}`);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Scans the CLI root directory and returns all valid tenant infos.
|
|
158
|
-
* @returns A list of TenantInfo objects found in {tenant-id}/info.json files.
|
|
159
|
-
*/
|
|
160
|
-
function getAllTenantsInfo() {
|
|
161
|
-
if (!fs.existsSync(rootDir))
|
|
162
|
-
return [];
|
|
163
|
-
const subDirs = fs
|
|
164
|
-
.readdirSync(rootDir)
|
|
165
|
-
.filter((entry) => fs.statSync(path.join(rootDir, entry)).isDirectory());
|
|
166
|
-
const tenants = [];
|
|
167
|
-
for (const dir of subDirs) {
|
|
168
|
-
const infoPath = path.join(rootDir, dir, 'info.json');
|
|
169
|
-
if (fs.existsSync(infoPath)) {
|
|
170
|
-
try {
|
|
171
|
-
const content = fs.readFileSync(infoPath, 'utf-8');
|
|
172
|
-
const data = JSON.parse(content);
|
|
173
|
-
if (data.tenantId && data.tenantName && data.organizationId && data.clientId) {
|
|
174
|
-
tenants.push({
|
|
175
|
-
tenantId: data.tenantId,
|
|
176
|
-
tenantName: data.tenantName,
|
|
177
|
-
organizationId: data.organizationId,
|
|
178
|
-
clientId: data.clientId,
|
|
179
|
-
authority: data.authority,
|
|
180
|
-
audience: data.audience,
|
|
181
|
-
baseUrl: data.baseUrl,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
console.error('\n Failed to read tenant info file', error.message);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return tenants;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Decodes a JWT without verifying its signature.
|
|
194
|
-
* @param {string} token - The access token string.
|
|
195
|
-
* @returns Decoded payload object or null if invalid.
|
|
196
|
-
*/
|
|
197
|
-
function decodeJwtPayload(token) {
|
|
198
|
-
try {
|
|
199
|
-
const base64Payload = token.split('.')[1];
|
|
200
|
-
const payload = Buffer.from(base64Payload, 'base64').toString('utf-8');
|
|
201
|
-
const decoded = JSON.parse(payload);
|
|
202
|
-
return {
|
|
203
|
-
tokenTenantId: decoded === null || decoded === void 0 ? void 0 : decoded[`${CLAIMS}/tenant_id`],
|
|
204
|
-
tokenOrgId: decoded === null || decoded === void 0 ? void 0 : decoded[`${CLAIMS}/org_id`],
|
|
205
|
-
tokenTenantName: decoded === null || decoded === void 0 ? void 0 : decoded[`${CLAIMS}/tenant_name`],
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
catch (error) {
|
|
209
|
-
console.error('\n Failed to decode access token:', error.message);
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { decodeJwtPayload } from './tenant-store';
|
|
11
|
-
export const AUTH0_DOMAIN = 'https://auth.sitecorecloud.io';
|
|
12
|
-
export const AUDIENCE = 'https://api.sitecorecloud.io';
|
|
13
|
-
export const BASE_URL = 'https://edge-platform.sitecorecloud.io/cs/api';
|
|
14
|
-
const GRANT_TYPE = 'client_credentials';
|
|
15
|
-
/**
|
|
16
|
-
* Performs the OAuth 2.0 client credentials flow to obtain a JWT access token
|
|
17
|
-
* from the Sitecore Identity Provider using the provided client credentials.
|
|
18
|
-
* @param {object} [args] - The arguments for client credentials flow
|
|
19
|
-
* @param {string} [args.clientId] - The client ID registered with Sitecore Identity
|
|
20
|
-
* @param {string} [args.clientSecret] - The client secret associated with the client ID
|
|
21
|
-
* @param {string} [args.organizationId] - The ID of the organization the client belongs to
|
|
22
|
-
* @param {string} [args.tenantId] - The tenant ID representing the specific Sitecore environment
|
|
23
|
-
* @param {string} [args.audience] - The API audience the token is intended for. Defaults to `AUDIENCE`
|
|
24
|
-
* @param {string} [args.authority] - The auth server base URL. Defaults to `AUTH0_DOMAIN`
|
|
25
|
-
* @param {string} [args.baseUrl] - The base URL for the API, used to construct the audience
|
|
26
|
-
* @returns A Promise that resolves to the access token response (including access token, token type, expiry, etc.)
|
|
27
|
-
* @throws Will log and exit the process if the request fails or returns a non-OK status
|
|
28
|
-
*/
|
|
29
|
-
export function clientCredentialsFlow(_a) {
|
|
30
|
-
return __awaiter(this, arguments, void 0, function* ({ clientId, clientSecret, organizationId, tenantId, audience = AUDIENCE, authority = AUTH0_DOMAIN, baseUrl = BASE_URL, }) {
|
|
31
|
-
const params = new URLSearchParams({
|
|
32
|
-
client_id: clientId,
|
|
33
|
-
client_secret: clientSecret !== null && clientSecret !== void 0 ? clientSecret : '',
|
|
34
|
-
organization_id: organizationId !== null && organizationId !== void 0 ? organizationId : '',
|
|
35
|
-
tenant_id: tenantId !== null && tenantId !== void 0 ? tenantId : '',
|
|
36
|
-
audience,
|
|
37
|
-
grant_type: GRANT_TYPE,
|
|
38
|
-
baseUrl: baseUrl !== null && baseUrl !== void 0 ? baseUrl : '',
|
|
39
|
-
});
|
|
40
|
-
try {
|
|
41
|
-
const response = yield fetch(`${authority}/oauth/token`, {
|
|
42
|
-
method: 'POST',
|
|
43
|
-
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
44
|
-
body: params.toString(),
|
|
45
|
-
});
|
|
46
|
-
const data = yield response.json();
|
|
47
|
-
if (!response.ok) {
|
|
48
|
-
throw new Error(data.error_description || data.error || 'Error during client credentials flow');
|
|
49
|
-
}
|
|
50
|
-
const decodedPayload = decodeJwtPayload(data.access_token) || {};
|
|
51
|
-
if (!(decodedPayload === null || decodedPayload === void 0 ? void 0 : decodedPayload.tokenTenantId) || !decodedPayload.tokenOrgId) {
|
|
52
|
-
throw new Error('\n Token is missing required claims tenant_id or org_id.');
|
|
53
|
-
}
|
|
54
|
-
const { tokenTenantId, tokenOrgId, tokenTenantName } = decodedPayload;
|
|
55
|
-
if (tenantId && tenantId !== tokenTenantId) {
|
|
56
|
-
throw new Error('\n Mismatch: Provided tenant ID does not match claims tenant ID.');
|
|
57
|
-
}
|
|
58
|
-
if (organizationId && organizationId !== tokenOrgId) {
|
|
59
|
-
throw new Error('\n Mismatch: Provided organization ID does not match claims organization ID.');
|
|
60
|
-
}
|
|
61
|
-
return { data, tokenOrgId, tokenTenantId, tokenTenantName };
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
console.error('\n Error during client credentials flow:', error instanceof Error ? error.message : error);
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { getActiveTenant, clearActiveTenant } from './tenant-state';
|
|
11
|
-
import { clientCredentialsFlow } from './flow';
|
|
12
|
-
import { writeTenantAuthInfo, readTenantAuthInfo, deleteTenantAuthInfo, readTenantInfo, } from './tenant-store';
|
|
13
|
-
/**
|
|
14
|
-
* Validates whether a given auth config is still valid (i.e., not expired).
|
|
15
|
-
* @param {TenantAuth} authInfo - The tenant auth configuration.
|
|
16
|
-
* @returns True if the token is still valid, false if expired.
|
|
17
|
-
*/
|
|
18
|
-
export function validateAuthInfo(authInfo) {
|
|
19
|
-
const now = new Date();
|
|
20
|
-
const expiry = new Date(authInfo.expires_at);
|
|
21
|
-
return now < expiry;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Renews the token for a given tenant using stored credentials.
|
|
25
|
-
* @param {TenantAuth} authInfo - Current authentication info for the tenant.
|
|
26
|
-
* @param {TenantInfo} tenantInfo - Public metadata about the tenant (e.g., clientId).
|
|
27
|
-
* @returns Promise<void>
|
|
28
|
-
* @throws If credentials are missing or renewal fails.
|
|
29
|
-
*/
|
|
30
|
-
export function renewClientToken(authInfo, tenantInfo) {
|
|
31
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
const result = yield clientCredentialsFlow({
|
|
33
|
-
clientId: tenantInfo.clientId,
|
|
34
|
-
clientSecret: authInfo.clientSecret,
|
|
35
|
-
organizationId: tenantInfo.organizationId,
|
|
36
|
-
tenantId: tenantInfo.tenantId,
|
|
37
|
-
audience: tenantInfo.audience,
|
|
38
|
-
authority: tenantInfo.authority,
|
|
39
|
-
baseUrl: tenantInfo.baseUrl,
|
|
40
|
-
});
|
|
41
|
-
const tenantId = tenantInfo.tenantId;
|
|
42
|
-
yield writeTenantAuthInfo(tenantId, {
|
|
43
|
-
clientSecret: authInfo.clientSecret,
|
|
44
|
-
access_token: result.data.access_token,
|
|
45
|
-
expires_in: result.data.expires_in,
|
|
46
|
-
expires_at: new Date(Date.now() + result.data.expires_in * 1000).toISOString(),
|
|
47
|
-
});
|
|
48
|
-
console.info(`\n Token for tenant ${tenantId} renewed.`);
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Ensures a valid token exists, renews it if expired.
|
|
53
|
-
* Returns tenant context if successful, otherwise null.
|
|
54
|
-
*/
|
|
55
|
-
export function renewAuthIfExpired() {
|
|
56
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
-
const tenantId = getActiveTenant();
|
|
58
|
-
if (!tenantId)
|
|
59
|
-
return null;
|
|
60
|
-
const authInfo = yield readTenantAuthInfo(tenantId);
|
|
61
|
-
if (!authInfo)
|
|
62
|
-
return null;
|
|
63
|
-
const isValid = validateAuthInfo(authInfo);
|
|
64
|
-
if (isValid) {
|
|
65
|
-
return { tenantId };
|
|
66
|
-
}
|
|
67
|
-
const tenantInfo = yield readTenantInfo(tenantId);
|
|
68
|
-
if (!tenantInfo)
|
|
69
|
-
return null;
|
|
70
|
-
console.info(`\n Token for tenant ${tenantId} is expired. Renewing...`);
|
|
71
|
-
try {
|
|
72
|
-
if (authInfo.clientSecret) {
|
|
73
|
-
yield renewClientToken(authInfo, tenantInfo);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// <TODO>: Implement Device auth token renewal.
|
|
77
|
-
throw new Error('\n Please use clientSecret for authentication.');
|
|
78
|
-
}
|
|
79
|
-
return { tenantId };
|
|
80
|
-
}
|
|
81
|
-
catch (err) {
|
|
82
|
-
console.error(`\n Failed to renew token for tenant '${tenantId}'`);
|
|
83
|
-
console.warn(`\n Cleaning up stale authentication data for tenant '${tenantId}'...`);
|
|
84
|
-
yield deleteTenantAuthInfo(tenantId);
|
|
85
|
-
clearActiveTenant();
|
|
86
|
-
console.info('\n You will need to login again to re-authenticate.');
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
const configDir = path.join(os.homedir(), '.sitecore', 'sitecore-tools');
|
|
5
|
-
const settingsFile = path.join(configDir, 'settings.json');
|
|
6
|
-
/**
|
|
7
|
-
* Gets the ID of the currently active tenant from settings.json.
|
|
8
|
-
* @returns The active tenant ID if present, otherwise null.
|
|
9
|
-
*/
|
|
10
|
-
export function getActiveTenant() {
|
|
11
|
-
var _a;
|
|
12
|
-
if (!fs.existsSync(settingsFile)) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
try {
|
|
16
|
-
const content = fs.readFileSync(settingsFile, 'utf-8');
|
|
17
|
-
const data = JSON.parse(content);
|
|
18
|
-
return (_a = data.activeTenant) !== null && _a !== void 0 ? _a : null;
|
|
19
|
-
}
|
|
20
|
-
catch (error) {
|
|
21
|
-
console.error(`\n Failed to read active tenant: ${error.message}`);
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Sets the currently active tenant by writing to settings.json.
|
|
27
|
-
* @param {string} tenantId - The tenant ID to set as active.
|
|
28
|
-
*/
|
|
29
|
-
export function setActiveTenant(tenantId) {
|
|
30
|
-
try {
|
|
31
|
-
if (!fs.existsSync(configDir)) {
|
|
32
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
33
|
-
}
|
|
34
|
-
const data = { activeTenant: tenantId };
|
|
35
|
-
fs.writeFileSync(settingsFile, JSON.stringify(data, null, 2));
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
console.error(`\n Failed to set active tenant '${tenantId}': ${error.message}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Clears the currently active tenant from settings.json by deleting the file.
|
|
43
|
-
*/
|
|
44
|
-
export function clearActiveTenant() {
|
|
45
|
-
try {
|
|
46
|
-
if (fs.existsSync(settingsFile)) {
|
|
47
|
-
fs.unlinkSync(settingsFile);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
console.error(`\n Failed to clear active tenant: ${error.message}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import * as fs from 'fs';
|
|
11
|
-
import * as path from 'path';
|
|
12
|
-
import * as os from 'os';
|
|
13
|
-
const CLAIMS = 'https://auth.sitecorecloud.io/claims';
|
|
14
|
-
const rootDir = path.join(os.homedir(), '.sitecore', 'sitecore-tools');
|
|
15
|
-
/**
|
|
16
|
-
* Get the full path to the tenant-specific folder.
|
|
17
|
-
* @param {string} tenantId - The tenant ID.
|
|
18
|
-
* @returns The absolute path to the tenant directory.
|
|
19
|
-
*/
|
|
20
|
-
function getTenantPath(tenantId) {
|
|
21
|
-
return path.join(rootDir, tenantId);
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Write the authentication configuration for a tenant.
|
|
25
|
-
* @param {string} tenantId - The tenant ID.
|
|
26
|
-
* @param {TenantAuth} authInfo - The tenant's auth data.
|
|
27
|
-
*/
|
|
28
|
-
export function writeTenantAuthInfo(tenantId, authInfo) {
|
|
29
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
-
try {
|
|
31
|
-
const dir = getTenantPath(tenantId);
|
|
32
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
33
|
-
fs.writeFileSync(path.join(dir, 'auth.json'), JSON.stringify(authInfo, null, 2));
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
console.error(`\n Failed to write auth.json for tenant '${tenantId}': ${error.message}`);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Read the authentication configuration for a tenant.
|
|
42
|
-
* @param {string} tenantId - The tenant ID.
|
|
43
|
-
* @returns Parsed auth config or null if not found or failed to read.
|
|
44
|
-
*/
|
|
45
|
-
export function readTenantAuthInfo(tenantId) {
|
|
46
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
-
const filePath = path.join(getTenantPath(tenantId), 'auth.json');
|
|
48
|
-
if (!fs.existsSync(filePath))
|
|
49
|
-
return null;
|
|
50
|
-
try {
|
|
51
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
52
|
-
return JSON.parse(raw);
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
console.error(`\n Failed to read auth.json for tenant '${tenantId}': ${error.message}`);
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Write the public metadata information for a tenant.
|
|
62
|
-
* @param {TenantInfo} info - The tenant info object.
|
|
63
|
-
*/
|
|
64
|
-
export function writeTenantInfo(info) {
|
|
65
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
-
try {
|
|
67
|
-
const dir = getTenantPath(info.tenantId);
|
|
68
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
69
|
-
fs.writeFileSync(path.join(dir, 'info.json'), JSON.stringify(info, null, 2));
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
console.error(`\n Failed to write info.json for tenant '${info.tenantId}': ${error.message}`);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Read the public metadata information for a tenant.
|
|
78
|
-
* @param {string} tenantId - The tenant ID.
|
|
79
|
-
* @returns Parsed tenant info or null if not found or failed to read.
|
|
80
|
-
*/
|
|
81
|
-
export function readTenantInfo(tenantId) {
|
|
82
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
-
const infoFilePath = path.join(getTenantPath(tenantId), 'info.json');
|
|
84
|
-
if (!fs.existsSync(infoFilePath)) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
try {
|
|
88
|
-
const content = fs.readFileSync(infoFilePath, 'utf-8');
|
|
89
|
-
return JSON.parse(content);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
console.error(`\n Failed to read info.json for tenant '${tenantId}': ${error.message}`);
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Deletes the stored auth.json file for the given tenant.
|
|
99
|
-
* @param {string} tenantId - The tenant ID.
|
|
100
|
-
*/
|
|
101
|
-
export function deleteTenantAuthInfo(tenantId) {
|
|
102
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
-
const filePath = path.join(getTenantPath(tenantId), 'auth.json');
|
|
104
|
-
try {
|
|
105
|
-
if (fs.existsSync(filePath)) {
|
|
106
|
-
fs.unlinkSync(filePath);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
console.error(`\n Failed to delete auth.json for tenant '${tenantId}': ${error.message}`);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Scans the CLI root directory and returns all valid tenant infos.
|
|
116
|
-
* @returns A list of TenantInfo objects found in {tenant-id}/info.json files.
|
|
117
|
-
*/
|
|
118
|
-
export function getAllTenantsInfo() {
|
|
119
|
-
if (!fs.existsSync(rootDir))
|
|
120
|
-
return [];
|
|
121
|
-
const subDirs = fs
|
|
122
|
-
.readdirSync(rootDir)
|
|
123
|
-
.filter((entry) => fs.statSync(path.join(rootDir, entry)).isDirectory());
|
|
124
|
-
const tenants = [];
|
|
125
|
-
for (const dir of subDirs) {
|
|
126
|
-
const infoPath = path.join(rootDir, dir, 'info.json');
|
|
127
|
-
if (fs.existsSync(infoPath)) {
|
|
128
|
-
try {
|
|
129
|
-
const content = fs.readFileSync(infoPath, 'utf-8');
|
|
130
|
-
const data = JSON.parse(content);
|
|
131
|
-
if (data.tenantId && data.tenantName && data.organizationId && data.clientId) {
|
|
132
|
-
tenants.push({
|
|
133
|
-
tenantId: data.tenantId,
|
|
134
|
-
tenantName: data.tenantName,
|
|
135
|
-
organizationId: data.organizationId,
|
|
136
|
-
clientId: data.clientId,
|
|
137
|
-
authority: data.authority,
|
|
138
|
-
audience: data.audience,
|
|
139
|
-
baseUrl: data.baseUrl,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
console.error('\n Failed to read tenant info file', error.message);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return tenants;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Decodes a JWT without verifying its signature.
|
|
152
|
-
* @param {string} token - The access token string.
|
|
153
|
-
* @returns Decoded payload object or null if invalid.
|
|
154
|
-
*/
|
|
155
|
-
export function decodeJwtPayload(token) {
|
|
156
|
-
try {
|
|
157
|
-
const base64Payload = token.split('.')[1];
|
|
158
|
-
const payload = Buffer.from(base64Payload, 'base64').toString('utf-8');
|
|
159
|
-
const decoded = JSON.parse(payload);
|
|
160
|
-
return {
|
|
161
|
-
tokenTenantId: decoded === null || decoded === void 0 ? void 0 : decoded[`${CLAIMS}/tenant_id`],
|
|
162
|
-
tokenOrgId: decoded === null || decoded === void 0 ? void 0 : decoded[`${CLAIMS}/org_id`],
|
|
163
|
-
tokenTenantName: decoded === null || decoded === void 0 ? void 0 : decoded[`${CLAIMS}/tenant_name`],
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
console.error('\n Failed to decode access token:', error.message);
|
|
168
|
-
return null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI arguments used for authentication and tenant identification.
|
|
3
|
-
*/
|
|
4
|
-
export interface TenantArgs {
|
|
5
|
-
/**
|
|
6
|
-
* OAuth2 client ID used to identify the application
|
|
7
|
-
*/
|
|
8
|
-
clientId: string;
|
|
9
|
-
/**
|
|
10
|
-
* Client secret used for client credentials flow
|
|
11
|
-
*/
|
|
12
|
-
clientSecret?: string;
|
|
13
|
-
/**
|
|
14
|
-
* Organization ID associated with the tenant
|
|
15
|
-
*/
|
|
16
|
-
organizationId?: string;
|
|
17
|
-
/**
|
|
18
|
-
* Tenant ID used for scoping the login
|
|
19
|
-
*/
|
|
20
|
-
tenantId?: string;
|
|
21
|
-
/**
|
|
22
|
-
* OAuth2 audience (e.g., API base URL the token is intended for)
|
|
23
|
-
*/
|
|
24
|
-
audience?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Auth authority/issuer URL (e.g., Sitecore identity endpoint)
|
|
27
|
-
*/
|
|
28
|
-
authority?: string;
|
|
29
|
-
/**
|
|
30
|
-
* Base URL for the target Sitecore Content Management API
|
|
31
|
-
*/
|
|
32
|
-
baseUrl?: string;
|
|
33
|
-
}
|
|
34
|
-
export interface TenantSettings {
|
|
35
|
-
/**
|
|
36
|
-
* Currently active tenant ID tracked by the CLI
|
|
37
|
-
*/
|
|
38
|
-
activeTenant?: string;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Auth configuration stored per tenant for accessing Sitecore APIs.
|
|
42
|
-
*/
|
|
43
|
-
export interface TenantAuth {
|
|
44
|
-
/**
|
|
45
|
-
* Access token issued by the identity provider
|
|
46
|
-
*/
|
|
47
|
-
access_token: string;
|
|
48
|
-
/**
|
|
49
|
-
* Token expiration duration in seconds
|
|
50
|
-
*/
|
|
51
|
-
expires_in: number;
|
|
52
|
-
/**
|
|
53
|
-
* Exact ISO timestamp when the token expires
|
|
54
|
-
*/
|
|
55
|
-
expires_at: string;
|
|
56
|
-
/**
|
|
57
|
-
* Secret used for client credentials flow and re-authenticate
|
|
58
|
-
*/
|
|
59
|
-
clientSecret?: string;
|
|
60
|
-
refresh_token?: string;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Public metadata for a known tenant.
|
|
64
|
-
*/
|
|
65
|
-
export interface TenantInfo {
|
|
66
|
-
/**
|
|
67
|
-
* Unique ID of the tenant
|
|
68
|
-
*/
|
|
69
|
-
tenantId: string;
|
|
70
|
-
/**
|
|
71
|
-
* Human-readable name of the tenant
|
|
72
|
-
*/
|
|
73
|
-
tenantName: string;
|
|
74
|
-
/**
|
|
75
|
-
* Organization ID the tenant belongs to
|
|
76
|
-
*/
|
|
77
|
-
organizationId: string;
|
|
78
|
-
/**
|
|
79
|
-
* Client ID associated with this tenant's authentication
|
|
80
|
-
*/
|
|
81
|
-
clientId: string;
|
|
82
|
-
/**
|
|
83
|
-
* OAuth2 audience (e.g., API base URL the token is intended for)
|
|
84
|
-
*/
|
|
85
|
-
audience: string;
|
|
86
|
-
/**
|
|
87
|
-
* Auth authority/issuer URL (e.g., Sitecore identity endpoint)
|
|
88
|
-
*/
|
|
89
|
-
authority: string;
|
|
90
|
-
/**
|
|
91
|
-
* Base URL for the target Sitecore Content Management API
|
|
92
|
-
*/
|
|
93
|
-
baseUrl: string;
|
|
94
|
-
}
|