@pnp/cli-microsoft365 10.8.0-beta.708bf27 → 10.8.0-beta.a51d886

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/Auth.js CHANGED
@@ -562,19 +562,93 @@ export class Auth {
562
562
  if (debug) {
563
563
  await logger.logToStderr('Trying to retrieve access token using federated identity...');
564
564
  }
565
- if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL || !process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN) {
566
- throw new CommandError('Federated identity is currently only supported in GitHub Actions.');
565
+ if (process.env.ACTIONS_ID_TOKEN_REQUEST_URL && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN) {
566
+ if (debug) {
567
+ await logger.logToStderr('ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN env variables found. The context is GitHub Actions...');
568
+ }
569
+ const federationToken = await this.getFederationTokenFromGithub(logger, debug);
570
+ return this.getAccessTokenWithFederatedToken(resource, federationToken, logger, debug);
571
+ }
572
+ else if (process.env.SYSTEM_OIDCREQUESTURI) {
573
+ if (debug) {
574
+ await logger.logToStderr('SYSTEM_OIDCREQUESTURI env variable found. The context is Azure DevOps...');
575
+ }
576
+ if (!process.env.SYSTEM_ACCESSTOKEN) {
577
+ throw new CommandError(`The SYSTEM_ACCESSTOKEN environment variable is not available. Please check the Azure DevOps pipeline task configuration. It should contain 'SYSTEM_ACCESSTOKEN: $(System.AccessToken)' in the env section.`);
578
+ }
579
+ const serviceConnectionId = process.env.AZURESUBSCRIPTION_SERVICE_CONNECTION_ID;
580
+ const serviceConnectionAppId = process.env.AZURESUBSCRIPTION_CLIENT_ID;
581
+ const serviceConnectionTenantId = process.env.AZURESUBSCRIPTION_TENANT_ID;
582
+ const useServiceConnection = serviceConnectionId && serviceConnectionAppId && serviceConnectionTenantId;
583
+ if (!useServiceConnection) {
584
+ if (debug) {
585
+ await logger.logToStderr('Not using a service connection. Run this command in an AzurePowerShell task to be able to use a service connection.');
586
+ }
587
+ if (!this.connection.appId || this.connection.tenant === 'common') {
588
+ throw new CommandError('The appId and tenant parameters are required when not using a service connection.');
589
+ }
590
+ }
591
+ else {
592
+ if (debug) {
593
+ if (this.connection.appId || this.connection.tenant !== 'common') {
594
+ await logger.logToStderr('When using a service connection, the appId and tenant values are updated to the values of the service connection.');
595
+ }
596
+ await logger.logToStderr(`Using service connection '${serviceConnectionId}' with app Id '${serviceConnectionAppId}' and tenant Id '${serviceConnectionTenantId}'...`);
597
+ }
598
+ this.connection.appId = serviceConnectionAppId;
599
+ this.connection.tenant = serviceConnectionTenantId;
600
+ }
601
+ const federationToken = await this.getFederationTokenFromAzureDevOps(logger, debug, serviceConnectionId);
602
+ return this.getAccessTokenWithFederatedToken(resource, federationToken, logger, debug);
603
+ }
604
+ else {
605
+ throw new CommandError('Federated identity is currently only supported in GitHub Actions and Azure DevOps.');
606
+ }
607
+ }
608
+ async getFederationTokenFromGithub(logger, debug) {
609
+ if (debug) {
610
+ await logger.logToStderr('Retrieving GitHub federation token...');
611
+ }
612
+ const requestOptions = {
613
+ url: `${process.env.ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${encodeURIComponent('api://AzureADTokenExchange')}`,
614
+ headers: {
615
+ Authorization: `Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`,
616
+ Accept: 'application/json',
617
+ 'x-anonymous': true
618
+ },
619
+ responseType: 'json'
620
+ };
621
+ const accessTokenResponse = await request.get(requestOptions);
622
+ return accessTokenResponse.value;
623
+ }
624
+ async getFederationTokenFromAzureDevOps(logger, debug, serviceConnectionId) {
625
+ if (debug) {
626
+ await logger.logToStderr('Retrieving Azure DevOps federation token...');
567
627
  }
628
+ const urlSuffix = serviceConnectionId ? `&serviceConnectionId=${serviceConnectionId}` : '';
629
+ const requestOptions = {
630
+ url: `${process.env.SYSTEM_OIDCREQUESTURI}?api-version=7.1${urlSuffix}`,
631
+ headers: {
632
+ Authorization: `Bearer ${process.env.SYSTEM_ACCESSTOKEN}`,
633
+ Accept: 'application/json',
634
+ 'Content-Type': 'application/json',
635
+ 'x-anonymous': true
636
+ },
637
+ responseType: 'json'
638
+ };
639
+ const accessTokenResponse = await request.post(requestOptions);
640
+ return accessTokenResponse.oidcToken;
641
+ }
642
+ async getAccessTokenWithFederatedToken(resource, federatedToken, logger, debug) {
568
643
  if (debug) {
569
- await logger.logToStderr('ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN env variables found. The context is GitHub Actions...');
644
+ await logger.logToStderr('Retrieving Entra ID Access Token with federated token...');
570
645
  }
571
- const federationToken = await this.getFederationTokenFromGithub(logger, debug);
572
646
  const queryParams = [
573
647
  'grant_type=client_credentials',
574
648
  `scope=${encodeURIComponent(`${resource}/.default`)}`,
575
649
  `client_id=${this.connection.appId}`,
576
650
  `client_assertion_type=${encodeURIComponent('urn:ietf:params:oauth:client-assertion-type:jwt-bearer')}`,
577
- `client_assertion=${federationToken}`
651
+ `client_assertion=${federatedToken}`
578
652
  ];
579
653
  const requestOptions = {
580
654
  url: `https://login.microsoftonline.com/${this.connection.tenant}/oauth2/v2.0/token`,
@@ -587,27 +661,13 @@ export class Auth {
587
661
  responseType: 'json'
588
662
  };
589
663
  const accessTokenResponse = await request.post(requestOptions);
664
+ const expiresIn = parseInt(accessTokenResponse.expires_in) * 1000;
665
+ const now = new Date();
590
666
  return {
591
667
  accessToken: accessTokenResponse.access_token,
592
- expiresOn: new Date(parseInt(accessTokenResponse.expires_on) * 1000)
668
+ expiresOn: new Date(now.getTime() + expiresIn)
593
669
  };
594
670
  }
595
- async getFederationTokenFromGithub(logger, debug) {
596
- if (debug) {
597
- await logger.logToStderr('Retrieving GitHub federation token...');
598
- }
599
- const requestOptions = {
600
- url: `${process.env.ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${encodeURIComponent('api://AzureADTokenExchange')}`,
601
- headers: {
602
- Authorization: `Bearer ${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN}`,
603
- accept: 'application/json',
604
- 'x-anonymous': true
605
- },
606
- responseType: 'json'
607
- };
608
- const accessTokenResponse = await request.get(requestOptions);
609
- return accessTokenResponse.value;
610
- }
611
671
  async ensureAccessTokenWithSecret(resource, logger, debug, fetchNew) {
612
672
  this.clientApplication = await this.getConfidentialClient(logger, debug, undefined, undefined, this.connection.secret);
613
673
  return this.clientApplication.acquireTokenByClientCredential({
@@ -37,7 +37,7 @@ class LoginCommand extends Command {
37
37
  }
38
38
  getRefinedSchema(schema) {
39
39
  return schema
40
- .refine(options => typeof options.appId !== 'undefined' || cli.getClientId() || options.authType === 'identity', {
40
+ .refine(options => typeof options.appId !== 'undefined' || cli.getClientId() || options.authType === 'identity' || options.authType === 'federatedIdentity', {
41
41
  message: `appId is required. TIP: use the "m365 setup" command to configure the default appId.`,
42
42
  path: ['appId']
43
43
  })
@@ -18,7 +18,6 @@ import { validation } from '../../utils/validation.js';
18
18
  import AnonymousCommand from '../base/AnonymousCommand.js';
19
19
  import commands from './commands.js';
20
20
  import { interactivePreset, powerShellPreset, scriptingPreset } from './setupPresets.js';
21
- import { optionsUtils } from '../../utils/optionsUtils.js';
22
21
  export var CliUsageMode;
23
22
  (function (CliUsageMode) {
24
23
  CliUsageMode["Interactively"] = "interactively";
@@ -228,7 +227,7 @@ class SetupCommand extends AnonymousCommand {
228
227
  });
229
228
  const appInfo = await entraApp.createAppRegistration({
230
229
  options,
231
- unknownOptions: optionsUtils.getUnknownOptions(options, this.options),
230
+ unknownOptions: {},
232
231
  apis,
233
232
  logger,
234
233
  verbose: this.verbose,
@@ -0,0 +1,52 @@
1
+ import { cli } from '../../../../cli/cli.js';
2
+ import { z } from 'zod';
3
+ import { zod } from '../../../../utils/zod.js';
4
+ import { globalOptionsZod } from '../../../../Command.js';
5
+ import commands from '../../commands.js';
6
+ import GraphCommand from '../../../base/GraphCommand.js';
7
+ import { odata } from '../../../../utils/odata.js';
8
+ import { formatting } from '../../../../utils/formatting.js';
9
+ const options = globalOptionsZod
10
+ .extend({
11
+ containerId: zod.alias('i', z.string())
12
+ })
13
+ .strict();
14
+ class SpeContainerPermissionListCommand extends GraphCommand {
15
+ get name() {
16
+ return commands.CONTAINER_PERMISSION_LIST;
17
+ }
18
+ get description() {
19
+ return 'Lists permissions of a SharePoint Embedded Container';
20
+ }
21
+ defaultProperties() {
22
+ return ['id', 'userPrincipalName', 'roles'];
23
+ }
24
+ get schema() {
25
+ return options;
26
+ }
27
+ async commandAction(logger, args) {
28
+ try {
29
+ if (this.verbose) {
30
+ await logger.logToStderr(`Retrieving permissions of a SharePoint Embedded Container with id '${args.options.containerId}'...`);
31
+ }
32
+ const containerPermission = await odata.getAllItems(`${this.resource}/v1.0/storage/fileStorage/containers/${formatting.encodeQueryParameter(args.options.containerId)}/permissions`);
33
+ if (!cli.shouldTrimOutput(args.options.output)) {
34
+ await logger.log(containerPermission);
35
+ }
36
+ else {
37
+ await logger.log(containerPermission.map(i => {
38
+ return {
39
+ id: i.id,
40
+ roles: i.roles.join(','),
41
+ userPrincipalName: i.grantedToV2.user.userPrincipalName
42
+ };
43
+ }));
44
+ }
45
+ }
46
+ catch (err) {
47
+ this.handleRejectedODataJsonPromise(err);
48
+ }
49
+ }
50
+ }
51
+ export default new SpeContainerPermissionListCommand();
52
+ //# sourceMappingURL=container-permission-list.js.map
@@ -3,6 +3,7 @@ export default {
3
3
  CONTAINER_ACTIVATE: `${prefix} container activate`,
4
4
  CONTAINER_GET: `${prefix} container get`,
5
5
  CONTAINER_LIST: `${prefix} container list`,
6
+ CONTAINER_PERMISSION_LIST: `${prefix} container permission list`,
6
7
  CONTAINERTYPE_ADD: `${prefix} containertype add`,
7
8
  CONTAINERTYPE_GET: `${prefix} containertype get`,
8
9
  CONTAINERTYPE_LIST: `${prefix} containertype list`
@@ -59,19 +59,25 @@ class SpoPageSectionAddCommand extends SpoCommand {
59
59
  };
60
60
  await request.post(requestOptions);
61
61
  }
62
- // get columns
63
- const columns = canvasContent
64
- .filter(c => typeof c.controlType === 'undefined');
65
62
  // get unique zoneIndex values given each section can have 1 or more
66
63
  // columns each assigned to the zoneIndex of the corresponding section
67
- const zoneIndices = columns
64
+ const zoneIndices = canvasContent
65
+ // Exclude the vertical section
66
+ .filter(c => c.position)
68
67
  .map(c => c.position.zoneIndex)
69
68
  .filter((value, index, array) => {
70
69
  return array.indexOf(value) === index;
71
70
  })
72
- .sort();
73
- // zoneIndex for the new section to add
74
- const zoneIndex = this.getSectionIndex(zoneIndices, args.options.order);
71
+ .sort((a, b) => a - b);
72
+ // Add a new zoneIndex at the end of the array
73
+ zoneIndices.push(zoneIndices.length > 0 ? zoneIndices[zoneIndices.length - 1] + 1 : 1);
74
+ // get section number. if not specified, get the last section
75
+ let section = args.options.order || zoneIndices.length;
76
+ if (section > zoneIndices.length) {
77
+ section = zoneIndices.length;
78
+ }
79
+ // zoneIndex that represents the section where the web part should be added
80
+ const zoneIndex = zoneIndices[section - 1];
75
81
  let zoneId;
76
82
  let backgroundControlToAdd = undefined;
77
83
  if (args.options.zoneEmphasis && ['image', 'gradient'].includes(args.options.zoneEmphasis.toLowerCase())) {
@@ -83,11 +89,17 @@ class SpoPageSectionAddCommand extends SpoCommand {
83
89
  canvasContent.push(backgroundControlToAdd);
84
90
  }
85
91
  }
92
+ // Increment the zoneIndex of all columns that are greater than or equal to the new zoneIndex
93
+ canvasContent.forEach((c) => {
94
+ if (c.position && c.position.zoneIndex >= zoneIndex) {
95
+ c.position.zoneIndex += 1;
96
+ }
97
+ });
86
98
  // get the list of columns to insert based on the selected template
87
99
  const columnsToAdd = this.getColumns(zoneIndex, args, zoneId);
88
100
  // insert the column in the right place in the array so that
89
101
  // it stays sorted ascending by zoneIndex
90
- let pos = canvasContent.findIndex(c => typeof c.controlType === 'undefined' && c.position && c.position.zoneIndex > zoneIndex);
102
+ let pos = canvasContent.findIndex(c => c.position && c.position.zoneIndex >= zoneIndex);
91
103
  if (pos === -1) {
92
104
  pos = canvasContent.length - 1;
93
105
  }
@@ -109,21 +121,6 @@ class SpoPageSectionAddCommand extends SpoCommand {
109
121
  this.handleRejectedODataJsonPromise(err);
110
122
  }
111
123
  }
112
- getSectionIndex(zoneIndices, order) {
113
- // zoneIndex of the first column on the page
114
- const minIndex = zoneIndices.length === 0 ? 0 : zoneIndices[0];
115
- // zoneIndex of the last column on the page
116
- const maxIndex = zoneIndices.length === 0 ? 0 : zoneIndices[zoneIndices.length - 1];
117
- if (!order || order > zoneIndices.length) {
118
- // no order specified, add section to the end
119
- return maxIndex === 0 ? 1 : maxIndex * 2;
120
- }
121
- // add to the beginning
122
- if (order === 1) {
123
- return minIndex / 2;
124
- }
125
- return zoneIndices[order - 2] + ((zoneIndices[order - 1] - zoneIndices[order - 2]) / 2);
126
- }
127
124
  getColumns(zoneIndex, args, zoneId) {
128
125
  const columns = [];
129
126
  let sectionIndex = 1;
@@ -0,0 +1,90 @@
1
+ import Global from '/docs/cmd/_global.mdx';
2
+ import Tabs from '@theme/Tabs';
3
+ import TabItem from '@theme/TabItem';
4
+
5
+ # spe container permission list
6
+
7
+ Lists permissions of a SharePoint Embedded Container
8
+
9
+ ## Usage
10
+
11
+ ```sh
12
+ m365 spe container permission list [options]
13
+ ```
14
+
15
+ ## Options
16
+
17
+ ```md definition-list
18
+ `-i, --containerId <id>`
19
+ : The ID of the SharePoint Embedded Container.
20
+ ```
21
+
22
+ <Global />
23
+
24
+ ## Examples
25
+
26
+ Lists Container permissions.
27
+
28
+ ```sh
29
+ m365 spe container permission list --containerId "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z"
30
+ ```
31
+
32
+ ## Response
33
+
34
+ <Tabs>
35
+ <TabItem value="JSON">
36
+
37
+ ```json
38
+ [
39
+ {
40
+ "id": "X2k6MCMuZnxtZW1iZXJzaGlwfGRlYnJhYkBuYWNoYW4zNjUub25taWNyb3NvZnQuY29t",
41
+ "roles": [
42
+ "owner"
43
+ ],
44
+ "grantedToV2": {
45
+ "user": {
46
+ "displayName": "John Doe",
47
+ "email": "john.doe@contoso.onmicrosoft.com",
48
+ "userPrincipalName": "john.doe@contoso.onmicrosoft.com"
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ ```
54
+
55
+ </TabItem>
56
+ <TabItem value="Text">
57
+
58
+ ```text
59
+ id userPrincipalName roles
60
+ -------------------------------------------------------------------- -------------------------------- ------
61
+ X2k6MCMuZnxtZW1iZXJzaGlwfGRlYnJhYkBuYWNoYW4zNjUub25taWNyb3NvZnQuY29t john.doe@contoso.onmicrosoft.com owner
62
+ ```
63
+
64
+ </TabItem>
65
+ <TabItem value="CSV">
66
+
67
+ ```csv
68
+ id,roles,userPrincipalName
69
+ X2k6MCMuZnxtZW1iZXJzaGlwfGRlYnJhYkBuYWNoYW4zNjUub25taWNyb3NvZnQuY29t,owner,john.doe@contoso.onmicrosoft.com
70
+ ```
71
+
72
+ </TabItem>
73
+ <TabItem value="Markdown">
74
+
75
+ ```md
76
+ # spe container permission list --containerId "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z"
77
+
78
+ Date: 3/3/2025
79
+
80
+ ## X2k6MCMuZnxtZW1iZXJzaGlwfGRlYnJhYkBuYWNoYW4zNjUub25taWNyb3NvZnQuY29t
81
+
82
+ Property | Value
83
+ ---------|-------
84
+ id | X2k6MCMuZnxtZW1iZXJzaGlwfGRlYnJhYkBuYWNoYW4zNjUub25taWNyb3NvZnQuY29t
85
+ roles | owner
86
+ userPrincipalName | john.doe@contoso.onmicrosoft.com
87
+ ```
88
+
89
+ </TabItem>
90
+ </Tabs>
@@ -32,7 +32,6 @@ m365 spo field get [options]
32
32
 
33
33
  `-t, --title [title]`
34
34
  : The display name (case-sensitive) of the field to retrieve. Specify either `id`, `title` or `internalName`.
35
- ```
36
35
 
37
36
  `--internalName [internalName]`
38
37
  : The internal name (case-sensitive) of the field to retrieve. Specify either `id`, `title` or `internalName`.