@mindline/sync 1.0.74 → 1.0.75
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/.vs/VSWorkspaceState.json +1 -1
- package/.vs/slnx.sqlite +0 -0
- package/.vs/sync/FileContentIndex/14dddfc3-43fc-4d99-b5ff-2695774c7325.vsidx +0 -0
- package/.vs/sync/FileContentIndex/5d07352f-b1a7-4c75-8bbb-e4a043235bc2.vsidx +0 -0
- package/.vs/sync/FileContentIndex/fb5d1ac5-8cdf-47e7-80da-383f4c5b9f68.vsidx +0 -0
- package/.vs/sync/v17/.wsuo +0 -0
- package/.vs/sync/v17/DocumentLayout.json +80 -53
- package/actors.json +20 -0
- package/hybridspa.ts +71 -42
- package/index.d.ts +12 -8
- package/index.ts +278 -32
- package/package.json +1 -1
- package/.vs/sync/FileContentIndex/e13ef3d7-5b17-4969-a066-2f079d220e7f.vsidx +0 -0
package/.vs/slnx.sqlite
CHANGED
|
Binary file
|
package/.vs/sync/v17/.wsuo
CHANGED
|
Binary file
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
"Version": 1,
|
|
3
3
|
"WorkspaceRootPath": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\",
|
|
4
4
|
"Documents": [
|
|
5
|
+
{
|
|
6
|
+
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\resources.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
|
|
7
|
+
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:resources.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\actors.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
|
|
11
|
+
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:actors.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
|
|
12
|
+
},
|
|
5
13
|
{
|
|
6
14
|
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\index.ts||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}",
|
|
7
15
|
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:index.ts||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}"
|
|
@@ -11,25 +19,24 @@
|
|
|
11
19
|
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:index.d.ts||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}"
|
|
12
20
|
},
|
|
13
21
|
{
|
|
14
|
-
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\
|
|
15
|
-
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:
|
|
22
|
+
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\hybridspa.ts||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}",
|
|
23
|
+
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:hybridspa.ts||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}"
|
|
16
24
|
},
|
|
17
25
|
{
|
|
18
|
-
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\
|
|
19
|
-
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:resources.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
|
|
26
|
+
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\node_modules\\@azure\\msal-browser\\src\\app\\IPublicClientApplication.ts||{0F2454B1-A556-402D-A7D0-1FDE7F99DEE0}"
|
|
20
27
|
},
|
|
21
28
|
{
|
|
22
|
-
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\
|
|
23
|
-
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:
|
|
29
|
+
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\package.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
|
|
30
|
+
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:package.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
|
|
24
31
|
}
|
|
25
32
|
],
|
|
26
33
|
"DocumentGroupContainers": [
|
|
27
34
|
{
|
|
28
|
-
"Orientation":
|
|
35
|
+
"Orientation": 1,
|
|
29
36
|
"VerticalTabListWidth": 256,
|
|
30
37
|
"DocumentGroups": [
|
|
31
38
|
{
|
|
32
|
-
"
|
|
39
|
+
"DockedHeight": 221,
|
|
33
40
|
"SelectedChildIndex": -1,
|
|
34
41
|
"Children": [
|
|
35
42
|
{
|
|
@@ -67,83 +74,103 @@
|
|
|
67
74
|
]
|
|
68
75
|
},
|
|
69
76
|
{
|
|
70
|
-
"
|
|
71
|
-
"SelectedChildIndex":
|
|
77
|
+
"DockedHeight": 299,
|
|
78
|
+
"SelectedChildIndex": 6,
|
|
72
79
|
"Children": [
|
|
73
80
|
{
|
|
74
81
|
"$type": "Document",
|
|
75
|
-
"DocumentIndex":
|
|
76
|
-
"Title": "
|
|
77
|
-
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\
|
|
78
|
-
"RelativeDocumentMoniker": "
|
|
79
|
-
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\
|
|
80
|
-
"RelativeToolTip": "
|
|
81
|
-
"ViewState": "
|
|
82
|
+
"DocumentIndex": 1,
|
|
83
|
+
"Title": "actors.json",
|
|
84
|
+
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\actors.json",
|
|
85
|
+
"RelativeDocumentMoniker": "actors.json",
|
|
86
|
+
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\actors.json",
|
|
87
|
+
"RelativeToolTip": "actors.json",
|
|
88
|
+
"ViewState": "AQIAAAAAAAAAAAAAAAAAABAAAAAEAAAA",
|
|
82
89
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
|
|
83
|
-
"WhenOpened": "2024-
|
|
90
|
+
"WhenOpened": "2024-04-01T07:44:39.353Z",
|
|
84
91
|
"EditorCaption": ""
|
|
85
92
|
},
|
|
86
93
|
{
|
|
87
94
|
"$type": "Document",
|
|
88
|
-
"DocumentIndex":
|
|
89
|
-
"Title": "
|
|
90
|
-
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\
|
|
91
|
-
"RelativeDocumentMoniker": "
|
|
92
|
-
"ToolTip": "C:\\Users\\ArvindSuthar\\
|
|
93
|
-
"RelativeToolTip": "
|
|
94
|
-
"ViewState": "
|
|
95
|
+
"DocumentIndex": 5,
|
|
96
|
+
"Title": "IPublicClientApplication.ts",
|
|
97
|
+
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\node_modules\\@azure\\msal-browser\\src\\app\\IPublicClientApplication.ts",
|
|
98
|
+
"RelativeDocumentMoniker": "..\\..\\..\\..\\node_modules\\@azure\\msal-browser\\src\\app\\IPublicClientApplication.ts",
|
|
99
|
+
"ToolTip": "C:\\Users\\ArvindSuthar\\node_modules\\@azure\\msal-browser\\src\\app\\IPublicClientApplication.ts",
|
|
100
|
+
"RelativeToolTip": "..\\..\\..\\..\\node_modules\\@azure\\msal-browser\\src\\app\\IPublicClientApplication.ts",
|
|
101
|
+
"ViewState": "AQIAABAAAAAAAAAAAAAAACIAAAAkAAAA",
|
|
95
102
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003213|",
|
|
96
|
-
"WhenOpened": "
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
"$type": "Document",
|
|
100
|
-
"DocumentIndex": 3,
|
|
101
|
-
"Title": "resources.json",
|
|
102
|
-
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\resources.json",
|
|
103
|
-
"RelativeDocumentMoniker": "resources.json",
|
|
104
|
-
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\resources.json",
|
|
105
|
-
"RelativeToolTip": "resources.json",
|
|
106
|
-
"ViewState": "AQIAAAgAAAAAAAAAAAAUwDkAAAABAAAA",
|
|
107
|
-
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
|
|
108
|
-
"WhenOpened": "2024-03-30T16:56:29.032Z",
|
|
103
|
+
"WhenOpened": "2024-04-01T01:09:13.977Z",
|
|
109
104
|
"EditorCaption": ""
|
|
110
105
|
},
|
|
111
106
|
{
|
|
112
107
|
"$type": "Document",
|
|
113
|
-
"DocumentIndex":
|
|
108
|
+
"DocumentIndex": 2,
|
|
114
109
|
"Title": "index.ts",
|
|
115
110
|
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\index.ts",
|
|
116
111
|
"RelativeDocumentMoniker": "index.ts",
|
|
117
112
|
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\index.ts",
|
|
118
113
|
"RelativeToolTip": "index.ts",
|
|
119
|
-
"ViewState": "
|
|
114
|
+
"ViewState": "AQIAAAAAAAAAAAAAAAAAAIQAAAAAAAAA",
|
|
120
115
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003213|",
|
|
121
|
-
"WhenOpened": "
|
|
116
|
+
"WhenOpened": "2024-03-31T04:25:14.781Z",
|
|
122
117
|
"EditorCaption": ""
|
|
123
|
-
}
|
|
124
|
-
]
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
"DockedWidth": 200,
|
|
128
|
-
"SelectedChildIndex": 0,
|
|
129
|
-
"Children": [
|
|
118
|
+
},
|
|
130
119
|
{
|
|
131
120
|
"$type": "Document",
|
|
132
|
-
"DocumentIndex":
|
|
121
|
+
"DocumentIndex": 4,
|
|
122
|
+
"Title": "hybridspa.ts",
|
|
123
|
+
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\hybridspa.ts",
|
|
124
|
+
"RelativeDocumentMoniker": "hybridspa.ts",
|
|
125
|
+
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\hybridspa.ts",
|
|
126
|
+
"RelativeToolTip": "hybridspa.ts",
|
|
127
|
+
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAkAAAAAAAAA",
|
|
128
|
+
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003213|",
|
|
129
|
+
"WhenOpened": "2024-03-31T03:57:20.961Z",
|
|
130
|
+
"EditorCaption": ""
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"$type": "Document",
|
|
134
|
+
"DocumentIndex": 3,
|
|
133
135
|
"Title": "index.d.ts",
|
|
134
136
|
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\index.d.ts",
|
|
135
137
|
"RelativeDocumentMoniker": "index.d.ts",
|
|
136
138
|
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\index.d.ts",
|
|
137
139
|
"RelativeToolTip": "index.d.ts",
|
|
138
|
-
"ViewState": "
|
|
140
|
+
"ViewState": "AQIAACgBAAAAAAAAAAAAAD4BAAAiAAAA",
|
|
139
141
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003213|",
|
|
140
|
-
"WhenOpened": "2024-
|
|
142
|
+
"WhenOpened": "2024-03-31T03:51:46.193Z",
|
|
143
|
+
"EditorCaption": ""
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"$type": "Document",
|
|
147
|
+
"DocumentIndex": 6,
|
|
148
|
+
"Title": "package.json",
|
|
149
|
+
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\package.json",
|
|
150
|
+
"RelativeDocumentMoniker": "package.json",
|
|
151
|
+
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\package.json",
|
|
152
|
+
"RelativeToolTip": "package.json",
|
|
153
|
+
"ViewState": "AQIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
154
|
+
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
|
|
155
|
+
"WhenOpened": "2024-03-30T18:10:14.136Z"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"$type": "Document",
|
|
159
|
+
"DocumentIndex": 0,
|
|
160
|
+
"Title": "resources.json",
|
|
161
|
+
"DocumentMoniker": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\resources.json",
|
|
162
|
+
"RelativeDocumentMoniker": "resources.json",
|
|
163
|
+
"ToolTip": "C:\\Users\\ArvindSuthar\\source\\repos\\front\\sync\\resources.json",
|
|
164
|
+
"RelativeToolTip": "resources.json",
|
|
165
|
+
"ViewState": "AQIAAAAAAAAAAAAAAAAAADkAAAABAAAA",
|
|
166
|
+
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
|
|
167
|
+
"WhenOpened": "2024-03-30T16:56:29.032Z",
|
|
141
168
|
"EditorCaption": ""
|
|
142
169
|
}
|
|
143
170
|
]
|
|
144
171
|
},
|
|
145
172
|
{
|
|
146
|
-
"
|
|
173
|
+
"DockedHeight": 200,
|
|
147
174
|
"SelectedChildIndex": -1,
|
|
148
175
|
"Children": [
|
|
149
176
|
{
|
|
@@ -153,7 +180,7 @@
|
|
|
153
180
|
]
|
|
154
181
|
},
|
|
155
182
|
{
|
|
156
|
-
"
|
|
183
|
+
"DockedHeight": 200,
|
|
157
184
|
"SelectedChildIndex": -1,
|
|
158
185
|
"Children": [
|
|
159
186
|
{
|
package/actors.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"type": "user",
|
|
4
|
+
"actor": "arvind@mindline.site",
|
|
5
|
+
"resource": "kv-syncproject",
|
|
6
|
+
"role": "Key Vault Certificate Officer",
|
|
7
|
+
"updatedby": "arvind@mindline.site",
|
|
8
|
+
"updatedon": "2023-09-06T15:36:45.7760714Z",
|
|
9
|
+
"resources": []
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "app",
|
|
13
|
+
"actor": "mindline1-sync-512169f5-38d1-4b57-be8b-967f2d0ae4c6",
|
|
14
|
+
"resource": "dev-subscription",
|
|
15
|
+
"role": "Contributor",
|
|
16
|
+
"updatedby": "arvind@mindline.site",
|
|
17
|
+
"updatedon": "2023-09-06T15:36:45.7760714Z",
|
|
18
|
+
"resources": []
|
|
19
|
+
}
|
|
20
|
+
]
|
package/hybridspa.ts
CHANGED
|
@@ -7,6 +7,9 @@ import {
|
|
|
7
7
|
TenantConfigInfo,
|
|
8
8
|
User
|
|
9
9
|
} from "./index";
|
|
10
|
+
import {
|
|
11
|
+
AccountInfo
|
|
12
|
+
} from "@azure/msal-common";
|
|
10
13
|
import {
|
|
11
14
|
IPublicClientApplication,
|
|
12
15
|
AuthenticationResult,
|
|
@@ -15,7 +18,7 @@ import { deserializeArray } from "class-transformer";
|
|
|
15
18
|
|
|
16
19
|
// helper functions
|
|
17
20
|
// TODO: this is where you want to trigger a re-authentication if token expires
|
|
18
|
-
|
|
21
|
+
async function mindlineDefineHeaders(
|
|
19
22
|
instance: IPublicClientApplication,
|
|
20
23
|
user: User
|
|
21
24
|
): Promise<Headers> {
|
|
@@ -23,42 +26,68 @@ export async function defineHeaders(
|
|
|
23
26
|
headers.append("Content-Type", "application/json");
|
|
24
27
|
headers.append("accept", "*/*");
|
|
25
28
|
// authorization header - if needed, retrieve and cache access token
|
|
26
|
-
if (user.
|
|
29
|
+
if (user.mindlineAccessToken == null || user.mindlineAccessToken === "") {
|
|
27
30
|
try {
|
|
28
|
-
let
|
|
29
|
-
|
|
31
|
+
let accounts: AccountInfo[] = instance.getAllAccounts();
|
|
32
|
+
let homeAccountId = user.oid + "." + user.tid;
|
|
33
|
+
let account: AccountInfo = null;
|
|
34
|
+
for (let i: number = 0; i < accounts.length; i++) {
|
|
35
|
+
if (accounts[i].homeAccountId == homeAccountId) {
|
|
36
|
+
account = accounts[i];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let response: AuthenticationResult = await instance.acquireTokenSilent({
|
|
40
|
+
scopes: ["api://8d95d21c-c378-4bb0-9f52-88c30d271e7a/Config.Write"],
|
|
41
|
+
account: account
|
|
30
42
|
});
|
|
31
|
-
user.
|
|
32
|
-
console.log("Front end token acquired: " + user.
|
|
43
|
+
user.mindlineAccessToken = response.accessToken; // cache access token
|
|
44
|
+
console.log("Front end token acquired silently: " + user.mindlineAccessToken.slice(0, 20));
|
|
33
45
|
}
|
|
34
46
|
catch (error: any) {
|
|
35
|
-
|
|
47
|
+
try {
|
|
48
|
+
console.log("Front end token silent acquisition failure: " + error);
|
|
49
|
+
// fallback to redirect if silent acquisition fails
|
|
50
|
+
let accounts: AccountInfo[] = instance.getAllAccounts();
|
|
51
|
+
let homeAccountId = user.oid + "." + user.tid;
|
|
52
|
+
let account: AccountInfo = null;
|
|
53
|
+
for (let i: number = 0; i < accounts.length; i++) {
|
|
54
|
+
if (accounts[i].homeAccountId == homeAccountId) {
|
|
55
|
+
account = accounts[i];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
instance.acquireTokenRedirect({
|
|
59
|
+
scopes: ["api://8d95d21c-c378-4bb0-9f52-88c30d271e7a/Config.Write"],
|
|
60
|
+
account: account
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
catch (error: any) {
|
|
64
|
+
console.log("Front end token popup acquisition failure: " + error);
|
|
65
|
+
}
|
|
36
66
|
}
|
|
37
67
|
}
|
|
38
|
-
headers.append("Authorization", `Bearer ${user.
|
|
68
|
+
headers.append("Authorization", `Bearer ${user.mindlineAccessToken}`);
|
|
39
69
|
return headers;
|
|
40
70
|
}
|
|
41
|
-
async function processErrors(response: Response): Promise<string> {
|
|
71
|
+
export async function processErrors(response: Response): Promise<string> {
|
|
42
72
|
let errorString: string = "";
|
|
43
73
|
if (response.status === 401) {
|
|
44
74
|
errorString = response.statusText;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
75
|
+
if (errorString != "") return errorString;
|
|
76
|
+
}
|
|
77
|
+
let data = await response.json();
|
|
78
|
+
if (data.error !== undefined) {
|
|
79
|
+
errorString = `Error: ${data.error.code} Message: ${data.error.message}`;
|
|
80
|
+
} else if (data.errors !== undefined) {
|
|
81
|
+
let errorArray = Object.keys(data.errors);
|
|
82
|
+
let errorlist: string = "";
|
|
83
|
+
errorString = errorArray.reduce(
|
|
84
|
+
(acc, curr) => acc + curr + ": " + data.errors[curr] + " ",
|
|
85
|
+
errorlist
|
|
86
|
+
);
|
|
87
|
+
} else if (data.title !== undefined) {
|
|
88
|
+
errorString = data.title;
|
|
89
|
+
} else {
|
|
90
|
+
debugger;
|
|
62
91
|
}
|
|
63
92
|
return errorString;
|
|
64
93
|
}
|
|
@@ -83,7 +112,7 @@ export async function adminDelete(
|
|
|
83
112
|
url.searchParams.append("workspaceId", workspaceId);
|
|
84
113
|
url.searchParams.append("email", user.mail);
|
|
85
114
|
// create headers
|
|
86
|
-
const headers = await
|
|
115
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
87
116
|
// make endpoint call
|
|
88
117
|
let options = { method: "DELETE", headers: headers };
|
|
89
118
|
try {
|
|
@@ -129,7 +158,7 @@ export async function adminsGet(
|
|
|
129
158
|
let url: URL = new URL(endpoint);
|
|
130
159
|
url.searchParams.append("workspaceId", workspaceID);
|
|
131
160
|
// create headers
|
|
132
|
-
const headers = await
|
|
161
|
+
const headers = await mindlineDefineHeaders(instance, user);
|
|
133
162
|
// make endpoint call
|
|
134
163
|
let options = { method: "GET", headers: headers };
|
|
135
164
|
try {
|
|
@@ -186,7 +215,7 @@ export async function adminPost(
|
|
|
186
215
|
// create admin endpoint
|
|
187
216
|
let endpoint: string = mindlineConfig.adminEndpoint();
|
|
188
217
|
// create headers
|
|
189
|
-
const headers = await
|
|
218
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
190
219
|
// create admin body
|
|
191
220
|
let adminBody: string = `
|
|
192
221
|
{"email": "${user.mail}",
|
|
@@ -225,7 +254,7 @@ export async function configConsentReadPut(instance: IPublicClientApplication, a
|
|
|
225
254
|
let url: URL = new URL(endpoint);
|
|
226
255
|
url.searchParams.append("configurationId", configId);
|
|
227
256
|
// create headers
|
|
228
|
-
const headers = await
|
|
257
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
229
258
|
// create body
|
|
230
259
|
let configConsentReadBody: string = `
|
|
231
260
|
{
|
|
@@ -266,7 +295,7 @@ export async function configConsentWritePut(instance: IPublicClientApplication,
|
|
|
266
295
|
let url: URL = new URL(endpoint);
|
|
267
296
|
url.searchParams.append("configurationId", configId);
|
|
268
297
|
// create headers
|
|
269
|
-
const headers = await
|
|
298
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
270
299
|
// create body
|
|
271
300
|
let configConsentWriteBody: string = `
|
|
272
301
|
{
|
|
@@ -318,7 +347,7 @@ export async function configDelete(
|
|
|
318
347
|
url = new URL(mindlineConfig.configEndpoint());
|
|
319
348
|
url.searchParams.append("configurationId", config.id);
|
|
320
349
|
// create headers
|
|
321
|
-
const headers = await
|
|
350
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
322
351
|
// make endpoint call
|
|
323
352
|
let options = { method: "DELETE", headers: headers };
|
|
324
353
|
try {
|
|
@@ -363,7 +392,7 @@ export async function configPost(
|
|
|
363
392
|
// create no parameter config endpoint
|
|
364
393
|
let endpoint: string = mindlineConfig.configEndpoint();
|
|
365
394
|
// create config headers
|
|
366
|
-
const headers = await
|
|
395
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
367
396
|
// create config body
|
|
368
397
|
let configBody: string = `
|
|
369
398
|
{
|
|
@@ -441,7 +470,7 @@ export async function configPut(
|
|
|
441
470
|
let url: URL = new URL(endpoint);
|
|
442
471
|
url.searchParams.append("configurationId", config.id);
|
|
443
472
|
// create config headers
|
|
444
|
-
const headers = await
|
|
473
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
445
474
|
// create config body
|
|
446
475
|
let configBody: string = `
|
|
447
476
|
{
|
|
@@ -517,7 +546,7 @@ export async function configsGet(
|
|
|
517
546
|
let url: URL = new URL(endpoint);
|
|
518
547
|
url.searchParams.append("workspaceId", workspaceID);
|
|
519
548
|
// create headers
|
|
520
|
-
const headers = await
|
|
549
|
+
const headers = await mindlineDefineHeaders(instance, user);
|
|
521
550
|
// make endpoint call
|
|
522
551
|
let options = { method: "GET", headers: headers };
|
|
523
552
|
try {
|
|
@@ -574,7 +603,7 @@ export async function initPost(
|
|
|
574
603
|
// create init endpoint
|
|
575
604
|
let endpoint: string = mindlineConfig.initEndpoint();
|
|
576
605
|
// create init headers
|
|
577
|
-
const headers = await
|
|
606
|
+
const headers = await mindlineDefineHeaders(instance, user);
|
|
578
607
|
// create init body
|
|
579
608
|
let initBody: string = `
|
|
580
609
|
{
|
|
@@ -634,7 +663,7 @@ export async function tenantDelete(
|
|
|
634
663
|
url.searchParams.append("tenantId", tenant.tid);
|
|
635
664
|
url.searchParams.append("workspaceId", workspaceId);
|
|
636
665
|
// create headers
|
|
637
|
-
const headers = await
|
|
666
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
638
667
|
// make tenant endpoint call
|
|
639
668
|
let options = { method: "DELETE", headers: headers };
|
|
640
669
|
try {
|
|
@@ -682,7 +711,7 @@ export async function tenantsGet(
|
|
|
682
711
|
let url: URL = new URL(endpoint);
|
|
683
712
|
url.searchParams.append("workspaceId", workspaceID);
|
|
684
713
|
// create headers
|
|
685
|
-
const headers = await
|
|
714
|
+
const headers = await mindlineDefineHeaders(instance, user);
|
|
686
715
|
// make endpoint call
|
|
687
716
|
let options = { method: "GET", headers: headers };
|
|
688
717
|
try {
|
|
@@ -742,7 +771,7 @@ export async function tenantPost(
|
|
|
742
771
|
let url: URL = new URL(endpoint);
|
|
743
772
|
url.searchParams.append("workspaceId", workspaceId);
|
|
744
773
|
// create tenant headers
|
|
745
|
-
const headers = await
|
|
774
|
+
const headers = await mindlineDefineHeaders(instance, addingUser);
|
|
746
775
|
// create tenant body
|
|
747
776
|
let tenantBody: string = `
|
|
748
777
|
{"tenantId": "${tenant.tid}",
|
|
@@ -792,7 +821,7 @@ export async function workspacePut(instance: IPublicClientApplication, authorize
|
|
|
792
821
|
url.searchParams.append("workspaceId", workspaceId);
|
|
793
822
|
url.searchParams.append("workspaceName", workspaceName);
|
|
794
823
|
// create workspace headers
|
|
795
|
-
const headers = await
|
|
824
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
796
825
|
let options = { method: "PUT", headers: headers };
|
|
797
826
|
// make config endpoint call
|
|
798
827
|
try {
|
|
@@ -838,7 +867,7 @@ export async function workspacesGet(
|
|
|
838
867
|
// create workspace endpoint
|
|
839
868
|
let url: URL = new URL(endpoint);
|
|
840
869
|
// create workspace headers
|
|
841
|
-
const headers = await
|
|
870
|
+
const headers = await mindlineDefineHeaders(instance, user);
|
|
842
871
|
// make workspace endpoint call
|
|
843
872
|
let options = { method: "GET", headers: headers };
|
|
844
873
|
try {
|
|
@@ -897,7 +926,7 @@ export async function readerPost(
|
|
|
897
926
|
let url: URL = new URL(readerEndpoint);
|
|
898
927
|
url.searchParams.append("configurationId", config.id);
|
|
899
928
|
// create headers
|
|
900
|
-
const headers = await
|
|
929
|
+
const headers = await mindlineDefineHeaders(instance, authorizedUser);
|
|
901
930
|
// make reader endpoint call
|
|
902
931
|
let options = { method: "POST", headers: headers };
|
|
903
932
|
try {
|
package/index.d.ts
CHANGED
|
@@ -10,7 +10,11 @@ declare module "@mindline/sync" {
|
|
|
10
10
|
version: string;
|
|
11
11
|
array: Array<Object> | null;
|
|
12
12
|
constructor();
|
|
13
|
-
}
|
|
13
|
+
}
|
|
14
|
+
export class azureConfig {
|
|
15
|
+
// azure graph REST API endpoints
|
|
16
|
+
static azureListRootAssignments: string = "https://management.azure.com/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId+eq+";
|
|
17
|
+
};
|
|
14
18
|
export class mindlineConfig {
|
|
15
19
|
static environmentTag: string;
|
|
16
20
|
// config API endpoints
|
|
@@ -72,7 +76,8 @@ declare module "@mindline/sync" {
|
|
|
72
76
|
workspaceIDs: string;
|
|
73
77
|
session: string;
|
|
74
78
|
spacode: string;
|
|
75
|
-
|
|
79
|
+
graphAccessToken: string;
|
|
80
|
+
mindlineAccessToken: string;
|
|
76
81
|
loginHint: string;
|
|
77
82
|
scopes: string[];
|
|
78
83
|
authTS: Date;
|
|
@@ -279,9 +284,7 @@ declare module "@mindline/sync" {
|
|
|
279
284
|
resources: ResourceNode[];
|
|
280
285
|
constructor(type: string, resource: string, cost: number);
|
|
281
286
|
}
|
|
282
|
-
//
|
|
283
|
-
// Azure AD Graph API
|
|
284
|
-
//
|
|
287
|
+
// ======================= Azure AD Graph API ===============================
|
|
285
288
|
export function groupsGet(instance: IPublicClientApplication, user: User | undefined, groupSearchString: string): Promise<{ groups: Group[], error: string }>;
|
|
286
289
|
export function oauth2PermissionGrantsGet(options: RequestInit, user: User, spid: string, oid: string): Promise<{grants: string, error: string}>;
|
|
287
290
|
export function requestAdminConsent(admin: User, tct: TenantConfigType): void;
|
|
@@ -295,9 +298,7 @@ declare module "@mindline/sync" {
|
|
|
295
298
|
export function userDelegatedScopesGet(instance: IPublicClientApplication, loggedInUser: User, tenant: Tenant): { scopes: string, id: string, error: string };
|
|
296
299
|
export function userDelegatedScopesRemove(instance: IPublicClientApplication, loggedInUser: User, tenant: Tenant, scope: string): boolean;
|
|
297
300
|
export function usersGet(instance: IPublicClientApplication, user: User | undefined): { users: string[], error: string };
|
|
298
|
-
//
|
|
299
|
-
// Mindline Config API
|
|
300
|
-
//
|
|
301
|
+
// ======================= Mindline Config API ===============================
|
|
301
302
|
export function configConsentForRead(instance: IPublicClientApplication, authorizedUser: User, configId: string, tid: string, consent: boolean): Promise<APIResult>;
|
|
302
303
|
export function configConsentForWrite(instance: IPublicClientApplication, authorizedUser: User, configId: string, tid: string, consent: boolean): Promise<APIResult>;
|
|
303
304
|
export function configEdit(
|
|
@@ -317,4 +318,7 @@ declare module "@mindline/sync" {
|
|
|
317
318
|
export function userAdd(instance: IPublicClientApplication, authorizedUser: User, user: User, workspaceId: string): APIResult;
|
|
318
319
|
export function userRemove(instance: IPublicClientApplication, authorizedUser: User, user: User, workspaceId: string): APIResult;
|
|
319
320
|
export function workspaceEdit(instance: IPublicClientApplication, authorizedUser: User, workspaceId: string, workspaceName: string): Promise<APIResult>;
|
|
321
|
+
// ======================= Azure REST API ===============================
|
|
322
|
+
export function canListRootAssignments(instance: IPublicClientApplication, user: User): Promise<boolean>;
|
|
323
|
+
export function elevateGlobalAdminToUserAccessAdmin(instance: IPublicClientApplication, user: User): Promise<boolean>;
|
|
320
324
|
}
|
package/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//index.ts - published interface - AAD implementations, facade to Mindline Config API
|
|
2
2
|
import * as signalR from "@microsoft/signalr"
|
|
3
|
+
import { AccountInfo } from "@azure/msal-common";
|
|
3
4
|
import { IPublicClientApplication, AuthenticationResult } from "@azure/msal-browser"
|
|
4
5
|
import { deserializeArray } from 'class-transformer';
|
|
5
|
-
import {
|
|
6
|
+
import { processErrors, adminDelete, adminPost, adminsGet, configConsentReadPut, configConsentWritePut, configDelete, configsGet, configPost, configPut, initPost, readerPost, tenantPost, tenantDelete, tenantsGet, workspacePut, workspacesGet } from './hybridspa';
|
|
6
7
|
import { version } from './package.json';
|
|
7
8
|
import users from "./users.json";
|
|
8
9
|
import tenants from "./tenants.json";
|
|
@@ -11,6 +12,7 @@ import workspaces from "./workspaces.json";
|
|
|
11
12
|
import tasksData from "./tasks";
|
|
12
13
|
import syncmilestones from './syncmilestones';
|
|
13
14
|
import resources from './resources';
|
|
15
|
+
import actors from './actors';
|
|
14
16
|
import { log } from "console";
|
|
15
17
|
const FILTER_FIELD = "workspaceIDs";
|
|
16
18
|
// called by unit tests
|
|
@@ -29,6 +31,11 @@ export class APIResult {
|
|
|
29
31
|
array: Array<Object> | null;
|
|
30
32
|
constructor() { this.result = true; this.status = 200; this.error = ""; this.version = version; this.array = null; }
|
|
31
33
|
}
|
|
34
|
+
export class azureConfig {
|
|
35
|
+
// azure graph REST API endpoints
|
|
36
|
+
static azureElevateAccess: string = "https://management.azure.com/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01";
|
|
37
|
+
static azureListRootAssignments: string = "https://management.azure.com/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId+eq+";
|
|
38
|
+
};
|
|
32
39
|
export class mindlineConfig {
|
|
33
40
|
static environmentTag: string = "dev";
|
|
34
41
|
// config API endpoints
|
|
@@ -120,7 +127,9 @@ export class User {
|
|
|
120
127
|
workspaceIDs: string;
|
|
121
128
|
session: string; // button text
|
|
122
129
|
spacode: string; // to get front end access token
|
|
123
|
-
|
|
130
|
+
graphAccessToken: string; // front end graph access token
|
|
131
|
+
mindlineAccessToken: string; // front end mindline access token
|
|
132
|
+
azureAccessToken: string; // front end azure access token
|
|
124
133
|
loginHint: string; // to help sign out without prompt
|
|
125
134
|
scopes: string[]; // to detect if incremental consent has happened
|
|
126
135
|
authTS: Date; // timestamp user was authenticated
|
|
@@ -137,7 +146,9 @@ export class User {
|
|
|
137
146
|
this.workspaceIDs = "";
|
|
138
147
|
this.session = "Sign In";
|
|
139
148
|
this.spacode = "";
|
|
140
|
-
this.
|
|
149
|
+
this.graphAccessToken = "";
|
|
150
|
+
this.mindlineAccessToken = "";
|
|
151
|
+
this.azureAccessToken = "";
|
|
141
152
|
this.loginHint = "";
|
|
142
153
|
this.scopes = new Array();
|
|
143
154
|
this.authTS = new Date(0);
|
|
@@ -425,7 +436,7 @@ export class InitInfo {
|
|
|
425
436
|
newuser.workspaceIDs = user.workspaceIDs;
|
|
426
437
|
newuser.session = user.session;
|
|
427
438
|
newuser.spacode = user.spacode;
|
|
428
|
-
newuser.
|
|
439
|
+
newuser.graphAccessToken = user.graphAccessToken;
|
|
429
440
|
newuser.loginHint = user.loginHint;
|
|
430
441
|
newuser.scopes = user.scopes;
|
|
431
442
|
newuser.authTS = new Date(user.authTS);
|
|
@@ -1231,36 +1242,53 @@ export class TenantNode {
|
|
|
1231
1242
|
}
|
|
1232
1243
|
export class ResourceArray {
|
|
1233
1244
|
resourceNodes: ResourceNode[];
|
|
1234
|
-
constructor(bClearLocalStorage: boolean) {
|
|
1245
|
+
constructor(bInitialize: boolean, bClearLocalStorage: boolean) {
|
|
1235
1246
|
this.resourceNodes = new Array<ResourceNode>();
|
|
1236
|
-
|
|
1247
|
+
if (bInitialize) {
|
|
1248
|
+
this.init(bClearLocalStorage);
|
|
1249
|
+
}
|
|
1237
1250
|
}
|
|
1238
|
-
// get
|
|
1251
|
+
// get resource data from localStorage or file
|
|
1239
1252
|
init(bClearLocalStorage: boolean): void {
|
|
1240
1253
|
console.log(`Calling ResourceArray::init(bClearLocalStorage: ${bClearLocalStorage ? "true" : "false"})`);
|
|
1241
1254
|
// if we have a non-empty string value stored, read it from localStorage
|
|
1242
1255
|
if (storageAvailable("localStorage")) {
|
|
1243
|
-
let result = localStorage.getItem("
|
|
1256
|
+
let result = localStorage.getItem("ResourceArray");
|
|
1244
1257
|
if (result != null && typeof result === "string" && result !== "") {
|
|
1245
1258
|
if (bClearLocalStorage) {
|
|
1246
|
-
localStorage.removeItem("
|
|
1259
|
+
localStorage.removeItem("ResourceArray");
|
|
1247
1260
|
}
|
|
1248
1261
|
else {
|
|
1249
|
-
|
|
1250
|
-
let
|
|
1251
|
-
|
|
1262
|
+
// read entire object from localstorage
|
|
1263
|
+
let raString: string = result;
|
|
1264
|
+
let resourceArray: ResourceArray = JSON.parse(raString);
|
|
1265
|
+
this.resourceNodes = resourceArray.resourceNodes;
|
|
1252
1266
|
return;
|
|
1253
1267
|
}
|
|
1254
1268
|
}
|
|
1255
1269
|
}
|
|
1256
|
-
// if storage unavailable or we were just asked to clear, read
|
|
1257
|
-
var
|
|
1270
|
+
// if storage unavailable or we were just asked to clear, read resources from file
|
|
1271
|
+
var resourceNodesString = JSON.stringify(resources);
|
|
1258
1272
|
try {
|
|
1259
|
-
this.resourceNodes = deserializeArray(ResourceNode,
|
|
1273
|
+
this.resourceNodes = deserializeArray(ResourceNode, resourceNodesString);
|
|
1260
1274
|
} catch (e) {
|
|
1261
1275
|
debugger;
|
|
1262
1276
|
}
|
|
1263
1277
|
}
|
|
1278
|
+
// read
|
|
1279
|
+
async read(instance: IPublicClientApplication, user: User): Promise<ResourceArray> {
|
|
1280
|
+
let resources: ResourceArray = new ResourceArray(false, false);
|
|
1281
|
+
resources.resourceNodes = await readResources(instance, user);
|
|
1282
|
+
return resources;
|
|
1283
|
+
}
|
|
1284
|
+
// save resource data to localstorage
|
|
1285
|
+
save(): void {
|
|
1286
|
+
// if we have localStorage, save resources
|
|
1287
|
+
if (storageAvailable("localStorage")) {
|
|
1288
|
+
let raString: string = JSON.stringify(this);
|
|
1289
|
+
localStorage.setItem("ResourceArray", raString);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1264
1292
|
}
|
|
1265
1293
|
export class ResourceNode {
|
|
1266
1294
|
type: string;
|
|
@@ -1276,14 +1304,89 @@ export class ResourceNode {
|
|
|
1276
1304
|
this.resources = new Array<ResourceNode>();
|
|
1277
1305
|
}
|
|
1278
1306
|
}
|
|
1307
|
+
export class ActorArray {
|
|
1308
|
+
actorNodes: ActorNode[];
|
|
1309
|
+
constructor(bClearLocalStorage: boolean) {
|
|
1310
|
+
this.actorNodes = new Array<ActorNode>();
|
|
1311
|
+
this.init(bClearLocalStorage);
|
|
1312
|
+
}
|
|
1313
|
+
// get initial data from localStorage or file
|
|
1314
|
+
init(bClearLocalStorage: boolean): void {
|
|
1315
|
+
console.log(`Calling ResourceArray::init(bClearLocalStorage: ${bClearLocalStorage ? "true" : "false"})`);
|
|
1316
|
+
// if we have a non-empty string value stored, read it from localStorage
|
|
1317
|
+
if (storageAvailable("localStorage")) {
|
|
1318
|
+
let result = localStorage.getItem("RBACActors");
|
|
1319
|
+
if (result != null && typeof result === "string" && result !== "") {
|
|
1320
|
+
if (bClearLocalStorage) {
|
|
1321
|
+
localStorage.removeItem("RBACActors");
|
|
1322
|
+
}
|
|
1323
|
+
else {
|
|
1324
|
+
let actorArrayString: string = result;
|
|
1325
|
+
let aaFromLocalStorage: ActorArray = JSON.parse(actorArrayString);
|
|
1326
|
+
this.actorNodes = aaFromLocalStorage.actorNodes;
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
// if storage unavailable or we were just asked to clear, read defaults to enable usable UI
|
|
1332
|
+
var actorsString = JSON.stringify(actors);
|
|
1333
|
+
try {
|
|
1334
|
+
this.actorNodes = deserializeArray(ActorNode, actorsString);
|
|
1335
|
+
} catch (e) {
|
|
1336
|
+
debugger;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
export class ActorNode {
|
|
1341
|
+
type: string;
|
|
1342
|
+
actor: string;
|
|
1343
|
+
resource: string;
|
|
1344
|
+
role: string;
|
|
1345
|
+
updatedby: string;
|
|
1346
|
+
updatedon: string;
|
|
1347
|
+
actors: ActorNode[];
|
|
1348
|
+
constructor(type: string, actor: string, resource: string, role: string, updatedby: string, updatedon: string) {
|
|
1349
|
+
this.type = type;
|
|
1350
|
+
this.actor = resource;
|
|
1351
|
+
this.resource = resource;
|
|
1352
|
+
this.role = role;
|
|
1353
|
+
this.updatedby = updatedby;
|
|
1354
|
+
this.updatedon = updatedon;
|
|
1355
|
+
this.actors = new Array<ActorNode>();
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1279
1358
|
// ======================= Azure AD Graph API ===============================
|
|
1359
|
+
// TODO: this is where you want to trigger a re-authentication if token expires
|
|
1360
|
+
async function graphDefineHeaders(
|
|
1361
|
+
instance: IPublicClientApplication,
|
|
1362
|
+
user: User
|
|
1363
|
+
): Promise<Headers> {
|
|
1364
|
+
const headers = new Headers();
|
|
1365
|
+
headers.append("Content-Type", "application/json");
|
|
1366
|
+
headers.append("accept", "*/*");
|
|
1367
|
+
// authorization header - if needed, retrieve and cache access token
|
|
1368
|
+
if (user.graphAccessToken == null || user.graphAccessToken === "") {
|
|
1369
|
+
try {
|
|
1370
|
+
let response: AuthenticationResult = await instance.acquireTokenByCode({
|
|
1371
|
+
code: user.spacode,
|
|
1372
|
+
});
|
|
1373
|
+
user.graphAccessToken = response.accessToken; // cache access token
|
|
1374
|
+
console.log("Front end token acquired: " + user.graphAccessToken.slice(0, 20));
|
|
1375
|
+
}
|
|
1376
|
+
catch (error: any) {
|
|
1377
|
+
console.log("Front end token failure: " + error);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
headers.append("Authorization", `Bearer ${user.graphAccessToken}`);
|
|
1381
|
+
return headers;
|
|
1382
|
+
}
|
|
1280
1383
|
export async function groupsGet(instance: IPublicClientApplication, user: User | undefined, groupSearchString: string): Promise<{ groups: Group[], error: string }> {
|
|
1281
1384
|
// need a logged in user to get graph users
|
|
1282
1385
|
if (user == null || user.spacode == "") {
|
|
1283
1386
|
return { groups: [], error: `500: invalid user passed to groupsGet` };
|
|
1284
1387
|
}
|
|
1285
1388
|
// create headers
|
|
1286
|
-
const headers = await
|
|
1389
|
+
const headers = await graphDefineHeaders(instance, user);
|
|
1287
1390
|
let options = { method: "GET", headers: headers };
|
|
1288
1391
|
// make /groups endpoint call
|
|
1289
1392
|
try {
|
|
@@ -1334,7 +1437,7 @@ export async function oauth2PermissionGrantsSet(instance: IPublicClientApplicati
|
|
|
1334
1437
|
let grantsurl: string = getGraphEndpoint(loggedInUser.authority);
|
|
1335
1438
|
grantsurl += graphConfig.graphOauth2PermissionGrantsPredicate + `/${id}`;
|
|
1336
1439
|
let scopesBody: string = `{ "scope": "${scopes}" }`;
|
|
1337
|
-
const headers = await
|
|
1440
|
+
const headers = await graphDefineHeaders(instance, loggedInUser);
|
|
1338
1441
|
let options: RequestInit = { method: "PATCH", headers: headers, body: scopesBody };
|
|
1339
1442
|
let response = await fetch(grantsurl, options);
|
|
1340
1443
|
if (response.status == 204 && response.statusText == "No Content") {
|
|
@@ -1520,12 +1623,12 @@ export async function tenantRelationshipsGetByDomain(loggedInUser: User, tenant:
|
|
|
1520
1623
|
// do we already have a valid tenant name? if so, nothing to add
|
|
1521
1624
|
if (tenant.name != null && tenant.name !== "") return false;
|
|
1522
1625
|
// if needed, retrieve and cache access token
|
|
1523
|
-
if (loggedInUser.
|
|
1626
|
+
if (loggedInUser.graphAccessToken != null && loggedInUser.graphAccessToken === "") {
|
|
1524
1627
|
console.log(`tenantRelationshipsGetByDomain called with invalid logged in user: ${loggedInUser.name}`);
|
|
1525
1628
|
try {
|
|
1526
|
-
let response: AuthenticationResult = await instance.acquireTokenByCode({ code: loggedInUser.spacode });
|
|
1527
|
-
loggedInUser.
|
|
1528
|
-
console.log("tenantRelationshipsGetByDomain: Front end token acquired: " + loggedInUser.
|
|
1629
|
+
let response: AuthenticationResult = await instance.acquireTokenByCode({ code: loggedInUser.spacode, scopes: ["user.read", "contacts.read", "CrossTenantInformation.ReadBasic.All"] });
|
|
1630
|
+
loggedInUser.graphAccessToken = response.accessToken; // cache access token on the user
|
|
1631
|
+
console.log("tenantRelationshipsGetByDomain: Front end token acquired: " + loggedInUser.graphAccessToken.slice(0, 20));
|
|
1529
1632
|
}
|
|
1530
1633
|
catch (error: any) {
|
|
1531
1634
|
console.log("tenantRelationshipsGetByDomain: Front end token failure: " + error);
|
|
@@ -1534,7 +1637,7 @@ export async function tenantRelationshipsGetByDomain(loggedInUser: User, tenant:
|
|
|
1534
1637
|
}
|
|
1535
1638
|
// prepare Authorization headers as part of options
|
|
1536
1639
|
const headers = new Headers();
|
|
1537
|
-
const bearer = `Bearer ${loggedInUser.
|
|
1640
|
+
const bearer = `Bearer ${loggedInUser.graphAccessToken}`;
|
|
1538
1641
|
headers.append("Authorization", bearer);
|
|
1539
1642
|
let options = { method: "GET", headers: headers };
|
|
1540
1643
|
// make tenant endpoint call
|
|
@@ -1578,11 +1681,11 @@ export async function tenantRelationshipsGetById(loggedInUser: User, tenant: Ten
|
|
|
1578
1681
|
console.log("**** tenantRelationshipsGetById");
|
|
1579
1682
|
if (debug) debugger;
|
|
1580
1683
|
// if needed, retrieve and cache access token
|
|
1581
|
-
if (loggedInUser.
|
|
1684
|
+
if (loggedInUser.graphAccessToken === "") {
|
|
1582
1685
|
try {
|
|
1583
|
-
let response: AuthenticationResult = await instance.acquireTokenByCode({ code: loggedInUser.spacode });
|
|
1584
|
-
loggedInUser.
|
|
1585
|
-
console.log("tenantRelationshipsGetById: Front end token acquired: " + loggedInUser.
|
|
1686
|
+
let response: AuthenticationResult = await instance.acquireTokenByCode({ code: loggedInUser.spacode, scopes: ["user.read", "contacts.read", "CrossTenantInformation.ReadBasic.All"] });
|
|
1687
|
+
loggedInUser.graphAccessToken = response.accessToken; // cache access token
|
|
1688
|
+
console.log("tenantRelationshipsGetById: Front end token acquired: " + loggedInUser.graphAccessToken.slice(0, 20));
|
|
1586
1689
|
}
|
|
1587
1690
|
catch (error: any) {
|
|
1588
1691
|
console.log("tenantRelationshipsGetById: Front end token failure: " + error);
|
|
@@ -1591,7 +1694,7 @@ export async function tenantRelationshipsGetById(loggedInUser: User, tenant: Ten
|
|
|
1591
1694
|
}
|
|
1592
1695
|
// prepare Authorization headers as part of options
|
|
1593
1696
|
const headers = new Headers();
|
|
1594
|
-
const bearer = `Bearer ${loggedInUser.
|
|
1697
|
+
const bearer = `Bearer ${loggedInUser.graphAccessToken}`;
|
|
1595
1698
|
headers.append("Authorization", bearer);
|
|
1596
1699
|
let options = { method: "GET", headers: headers };
|
|
1597
1700
|
// make tenant endpoint call
|
|
@@ -1648,7 +1751,7 @@ export async function tenantUnauthenticatedLookup(tenant: Tenant, debug: boolean
|
|
|
1648
1751
|
openidEndpoint += "/.well-known/openid-configuration";
|
|
1649
1752
|
console.log("Attempting GET from openid well-known endpoint: ", openidEndpoint);
|
|
1650
1753
|
response = await fetch(openidEndpoint);
|
|
1651
|
-
if (response.status == 200
|
|
1754
|
+
if (response.status == 200) {
|
|
1652
1755
|
let data = await response.json();
|
|
1653
1756
|
if (data) {
|
|
1654
1757
|
// store tenant ID and authority
|
|
@@ -1688,7 +1791,7 @@ export async function userDelegatedScopesGet(instance: IPublicClientApplication,
|
|
|
1688
1791
|
return { scopes: null, id: null, error: `500: invalid parameter(s) passed to getUserDelegatedScopes` };
|
|
1689
1792
|
}
|
|
1690
1793
|
// create headers
|
|
1691
|
-
const headers = await
|
|
1794
|
+
const headers = await graphDefineHeaders(instance, loggedInUser);
|
|
1692
1795
|
let options: RequestInit = { method: "GET", headers: headers };
|
|
1693
1796
|
try {
|
|
1694
1797
|
// first, cache Graph resource ID (service principal) for this tenant if we don't have it already
|
|
@@ -1744,12 +1847,12 @@ export async function userDelegatedScopesRemove(instance: IPublicClientApplicati
|
|
|
1744
1847
|
export async function usersGet(instance: IPublicClientApplication, user: User | undefined): Promise<{ users: string[], error: string }> {
|
|
1745
1848
|
// need a logged in user to get graph users
|
|
1746
1849
|
if (user == null || user.spacode == "") {
|
|
1747
|
-
return { users: [], error: `500: invalid user passed to
|
|
1850
|
+
return { users: [], error: `500: invalid user passed to usersGet` };
|
|
1748
1851
|
}
|
|
1749
1852
|
// make /users endpoint call
|
|
1750
1853
|
try {
|
|
1751
1854
|
// create headers
|
|
1752
|
-
const headers = await
|
|
1855
|
+
const headers = await graphDefineHeaders(instance, user);
|
|
1753
1856
|
let options = { method: "GET", headers: headers };
|
|
1754
1857
|
let usersEndpoint = getGraphEndpoint(user.authority);
|
|
1755
1858
|
usersEndpoint += graphConfig.graphUsersPredicate;
|
|
@@ -1844,7 +1947,8 @@ export async function configsRefresh(instance: IPublicClientApplication, authori
|
|
|
1844
1947
|
export async function initGet(instance: IPublicClientApplication, user: User, ii: InitInfo, tasks: TaskArray, debug: boolean): Promise<APIResult> {
|
|
1845
1948
|
console.log(`>>>>>> initGet`);
|
|
1846
1949
|
let result: APIResult = new APIResult();
|
|
1847
|
-
if (debug)
|
|
1950
|
+
if (debug)
|
|
1951
|
+
debugger;
|
|
1848
1952
|
// lookup authority for this user (the lookup call does it based on domain, but TID works as well to find authority)
|
|
1849
1953
|
let tenant: Tenant = new Tenant();
|
|
1850
1954
|
tenant.tid = user.tid;
|
|
@@ -2135,4 +2239,146 @@ async function workspaceInfoGet(instance: IPublicClientApplication, user: User,
|
|
|
2135
2239
|
result.result = false;
|
|
2136
2240
|
result.status = 500;
|
|
2137
2241
|
return result;
|
|
2242
|
+
}
|
|
2243
|
+
// ======================= Azure REST API ===============================
|
|
2244
|
+
// TODO: this is where you want to trigger a re-authentication if token expires
|
|
2245
|
+
async function azureDefineHeaders(
|
|
2246
|
+
instance: IPublicClientApplication,
|
|
2247
|
+
user: User
|
|
2248
|
+
): Promise<Headers> {
|
|
2249
|
+
const headers = new Headers();
|
|
2250
|
+
headers.append("Content-Type", "application/json");
|
|
2251
|
+
headers.append("accept", "*/*");
|
|
2252
|
+
// authorization header - if needed, retrieve and cache access token
|
|
2253
|
+
if (user.azureAccessToken == null || user.azureAccessToken === "") {
|
|
2254
|
+
try {
|
|
2255
|
+
let accounts: AccountInfo[] = instance.getAllAccounts();
|
|
2256
|
+
let homeAccountId = user.oid + "." + user.tid;
|
|
2257
|
+
let account: AccountInfo = null;
|
|
2258
|
+
for (let i: number = 0; i < accounts.length; i++) {
|
|
2259
|
+
if (accounts[i].homeAccountId == homeAccountId) {
|
|
2260
|
+
account = accounts[i];
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
debugger;
|
|
2264
|
+
let response: AuthenticationResult = await instance.acquireTokenSilent({
|
|
2265
|
+
scopes: ["https://management.azure.com/user_impersonation"],
|
|
2266
|
+
account: account
|
|
2267
|
+
});
|
|
2268
|
+
user.azureAccessToken = response.accessToken; // cache access token
|
|
2269
|
+
console.log("Front end token acquired silently: " + user.azureAccessToken.slice(0, 20));
|
|
2270
|
+
}
|
|
2271
|
+
catch (error: any) {
|
|
2272
|
+
try {
|
|
2273
|
+
console.log("Front end token silent acquisition failure: " + error);
|
|
2274
|
+
// fallback to redirect if silent acquisition fails
|
|
2275
|
+
let accounts: AccountInfo[] = instance.getAllAccounts();
|
|
2276
|
+
let homeAccountId = user.oid + "." + user.tid;
|
|
2277
|
+
let account: AccountInfo = null;
|
|
2278
|
+
for (let i: number = 0; i < accounts.length; i++) {
|
|
2279
|
+
if (accounts[i].homeAccountId == homeAccountId) {
|
|
2280
|
+
account = accounts[i];
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
instance.acquireTokenRedirect({
|
|
2284
|
+
scopes: ["https://management.azure.com/user_impersonation"],
|
|
2285
|
+
account: account
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
catch (error: any) {
|
|
2289
|
+
console.log("Front end token popup acquisition failure: " + error);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
headers.append("Authorization", `Bearer ${user.azureAccessToken}`);
|
|
2294
|
+
return headers;
|
|
2295
|
+
}
|
|
2296
|
+
export async function canListRootAssignments(instance: IPublicClientApplication, user: User): Promise<boolean> {
|
|
2297
|
+
// need a logged in user to call Azure REST API
|
|
2298
|
+
if (user == null || user.spacode == "") {
|
|
2299
|
+
return false;
|
|
2300
|
+
}
|
|
2301
|
+
// make Azure REST API call
|
|
2302
|
+
try {
|
|
2303
|
+
// create headers
|
|
2304
|
+
const headers = await azureDefineHeaders(instance, user);
|
|
2305
|
+
let options = { method: "GET", headers: headers };
|
|
2306
|
+
let listrootassignmentsEndpoint: string = azureConfig.azureListRootAssignments;
|
|
2307
|
+
listrootassignmentsEndpoint += "'";
|
|
2308
|
+
listrootassignmentsEndpoint += user.oid;
|
|
2309
|
+
listrootassignmentsEndpoint += "'";
|
|
2310
|
+
let response = await fetch(listrootassignmentsEndpoint, options);
|
|
2311
|
+
if (response.status == 200) {
|
|
2312
|
+
let data = await response.json();
|
|
2313
|
+
debugger;
|
|
2314
|
+
console.log("Successful call to Azure Resource Graph list root assignments");
|
|
2315
|
+
}
|
|
2316
|
+
else {
|
|
2317
|
+
console.log(await processErrors(response));
|
|
2318
|
+
return false;
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
catch (error: any) {
|
|
2322
|
+
console.log(error);
|
|
2323
|
+
return false;
|
|
2324
|
+
}
|
|
2325
|
+
return true;
|
|
2326
|
+
}
|
|
2327
|
+
export async function elevateGlobalAdminToUserAccessAdmin(instance: IPublicClientApplication, user: User): Promise<boolean> {
|
|
2328
|
+
// need a logged in user to call Azure REST API
|
|
2329
|
+
if (user == null || user.spacode == "") {
|
|
2330
|
+
return false;
|
|
2331
|
+
}
|
|
2332
|
+
// make Azure REST API call
|
|
2333
|
+
try {
|
|
2334
|
+
// create headers
|
|
2335
|
+
const headers = await azureDefineHeaders(instance, user);
|
|
2336
|
+
let options = { method: "POST", headers: headers };
|
|
2337
|
+
let elevateaccessEndpoint: string = azureConfig.azureElevateAccess;
|
|
2338
|
+
let response = await fetch(elevateaccessEndpoint, options);
|
|
2339
|
+
if (response.status == 200) {
|
|
2340
|
+
console.log("Successful call to Azure Resource Graph list root assignments");
|
|
2341
|
+
}
|
|
2342
|
+
else {
|
|
2343
|
+
console.log(await processErrors(response));
|
|
2344
|
+
return false;
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
catch (error: any) {
|
|
2348
|
+
console.log(error);
|
|
2349
|
+
return false;
|
|
2350
|
+
}
|
|
2351
|
+
return true;
|
|
2352
|
+
}
|
|
2353
|
+
async function readResources(instance: IPublicClientApplication, user: User): Promise<ResourceNode[]> {
|
|
2354
|
+
// need a logged in user to call Azure REST API
|
|
2355
|
+
let resources: ResourceNode[] = new Array<ResourceNode>();
|
|
2356
|
+
if (user == null || user.spacode == "") {
|
|
2357
|
+
return resources;
|
|
2358
|
+
}
|
|
2359
|
+
// make Azure REST API call
|
|
2360
|
+
try {
|
|
2361
|
+
// create headers
|
|
2362
|
+
const headers = await azureDefineHeaders(instance, user);
|
|
2363
|
+
let options = { method: "GET", headers: headers };
|
|
2364
|
+
let listrootassignmentsEndpoint: string = azureConfig.azureListRootAssignments;
|
|
2365
|
+
listrootassignmentsEndpoint += "'";
|
|
2366
|
+
listrootassignmentsEndpoint += user.oid;
|
|
2367
|
+
listrootassignmentsEndpoint += "'";
|
|
2368
|
+
let response = await fetch(listrootassignmentsEndpoint, options);
|
|
2369
|
+
if (response.status == 200) {
|
|
2370
|
+
let data = await response.json();
|
|
2371
|
+
debugger;
|
|
2372
|
+
console.log("Successful call to Azure Resource Graph list root assignments");
|
|
2373
|
+
}
|
|
2374
|
+
else {
|
|
2375
|
+
console.log(await processErrors(response));
|
|
2376
|
+
return false;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
catch (error: any) {
|
|
2380
|
+
console.log(error);
|
|
2381
|
+
return false;
|
|
2382
|
+
}
|
|
2383
|
+
return true;
|
|
2138
2384
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindline/sync",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.75",
|
|
5
5
|
"types": "index.d.ts",
|
|
6
6
|
"exports": "./index.ts",
|
|
7
7
|
"description": "sync is a node.js package encapsulating javscript classes required for configuring Mindline sync service.",
|
|
Binary file
|