@kwiz/common 1.0.5 → 1.0.7
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/.madgerc +3 -0
- package/dist/helpers/browser.d.ts +12 -5
- package/dist/helpers/browser.js +9 -6
- package/dist/helpers/browser.js.map +1 -1
- package/dist/helpers/date.js +10 -5
- package/dist/helpers/date.js.map +1 -1
- package/dist/helpers/debug.js +3 -3
- package/dist/helpers/debug.js.map +1 -1
- package/dist/helpers/objects.d.ts +2 -0
- package/dist/helpers/objects.js +17 -2
- package/dist/helpers/objects.js.map +1 -1
- package/dist/helpers/strings.js +2 -1
- package/dist/helpers/strings.js.map +1 -1
- package/dist/types/auth.d.ts +40 -0
- package/dist/types/auth.js +17 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/libs/msal.types.d.ts +1 -15
- package/dist/types/libs/msal.types.js +1 -33
- package/dist/types/libs/msal.types.js.map +1 -1
- package/dist/types/rest.types.d.ts +2 -0
- package/dist/utils/auth/adal.d.ts +3 -0
- package/dist/utils/auth/adal.js +35 -0
- package/dist/utils/auth/adal.js.map +1 -0
- package/dist/utils/auth/common.d.ts +3 -0
- package/dist/utils/auth/common.js +16 -0
- package/dist/utils/auth/common.js.map +1 -0
- package/dist/utils/auth/discovery.d.ts +5 -0
- package/dist/utils/auth/discovery.js +77 -0
- package/dist/utils/auth/discovery.js.map +1 -0
- package/dist/utils/auth/index.d.ts +2 -0
- package/dist/utils/auth/index.js +19 -0
- package/dist/utils/auth/index.js.map +1 -0
- package/dist/utils/auth/msal.d.ts +4 -0
- package/dist/utils/auth/msal.js +59 -0
- package/dist/utils/auth/msal.js.map +1 -0
- package/dist/utils/axios.d.ts +6 -0
- package/dist/utils/axios.js +30 -0
- package/dist/utils/axios.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +10 -7
- package/src/helpers/browser.ts +29 -11
- package/src/helpers/date.ts +10 -6
- package/src/helpers/debug.ts +4 -4
- package/src/helpers/objects.ts +17 -2
- package/src/helpers/strings.test.js +14 -2
- package/src/helpers/strings.ts +2 -1
- package/src/types/auth.ts +46 -0
- package/src/types/index.ts +1 -1
- package/src/types/libs/msal.types.ts +3 -38
- package/src/types/rest.types.ts +2 -0
- package/src/utils/auth/common.ts +9 -0
- package/src/utils/auth/discovery.ts +92 -0
- package/src/utils/auth/index.ts +3 -0
- package/src/utils/index.ts +1 -0
package/src/helpers/objects.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { makeUniqueArray } from "./collections.base";
|
|
2
2
|
import { jsonParse } from "./json";
|
|
3
|
-
import { isDate, isFunction, isNotEmptyArray, isNullOrEmptyString, isNullOrUndefined, isObject, isPrimitiveValue, primitiveTypes } from "./typecheckers";
|
|
3
|
+
import { isDate, isFunction, isNotEmptyArray, isNullOrEmptyString, isNullOrUndefined, isObject, isPrimitiveValue, isString, primitiveTypes } from "./typecheckers";
|
|
4
4
|
|
|
5
5
|
/** global window, safe for testing and environments without a browser */
|
|
6
6
|
export var $w = typeof window === "undefined" ? {
|
|
7
7
|
setTimeout: setTimeout,
|
|
8
|
-
clearTimeout: clearTimeout
|
|
8
|
+
clearTimeout: clearTimeout,
|
|
9
|
+
location: {
|
|
10
|
+
href: "", host: ""
|
|
11
|
+
}
|
|
9
12
|
} as any as Window : window;
|
|
10
13
|
|
|
11
14
|
/** wrapper for hasOwnProperty that satisfies https://eslint.org/docs/latest/rules/no-prototype-builtins */
|
|
@@ -253,4 +256,16 @@ class DefaultProp<T>{
|
|
|
253
256
|
/** creates a safe property, if the value is null/undefined or empty string - it will return the default value. */
|
|
254
257
|
export function GetDefaultProp<T>(defaultValue: T | (() => T), initialValue?: T, isValid?: (value: T) => boolean) {
|
|
255
258
|
return new DefaultProp(defaultValue, initialValue, isValid);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Get string error message from an error object */
|
|
262
|
+
export function GetError(error: any, defaultError: string = "Unknown error"): string {
|
|
263
|
+
const err = isNullOrUndefined(error)
|
|
264
|
+
? defaultError
|
|
265
|
+
: isString(error)
|
|
266
|
+
? error
|
|
267
|
+
: isString((error as Error).message)
|
|
268
|
+
? error.message
|
|
269
|
+
: defaultError;
|
|
270
|
+
return err.length > 0 ? err : defaultError;
|
|
256
271
|
}
|
|
@@ -4,6 +4,12 @@ import { capitalizeFirstLetter, escapeXml, replaceAll, replaceRegex } from './st
|
|
|
4
4
|
|
|
5
5
|
test('replaceAll', t => {
|
|
6
6
|
assert.strictEqual(replaceAll("hello old#@! world old#@! !", "old#@!", "new!@$"), "hello new!@$ world new!@$ !");
|
|
7
|
+
|
|
8
|
+
//this failed since the input find included protected regex characters.
|
|
9
|
+
//escapeRegExp needs to fix that
|
|
10
|
+
const source = "string with special regex[:(s:) chars";
|
|
11
|
+
const result = "string with special regex[~~(s~~) chars";
|
|
12
|
+
assert.strictEqual(replaceAll(source, source, result), result);
|
|
7
13
|
});
|
|
8
14
|
|
|
9
15
|
test('capitalizeFirstLetter', async t => {
|
|
@@ -30,7 +36,7 @@ test('escapeXml', async t => {
|
|
|
30
36
|
|
|
31
37
|
test('replaceRegex', t => {
|
|
32
38
|
/** Match anything between {zone:*} */
|
|
33
|
-
var
|
|
39
|
+
var match = /{zone:\w+}/gi;
|
|
34
40
|
|
|
35
41
|
var source = `text {zone:one} {zone:two}
|
|
36
42
|
more text
|
|
@@ -39,5 +45,11 @@ more text
|
|
|
39
45
|
more text
|
|
40
46
|
THREE`;
|
|
41
47
|
|
|
42
|
-
assert.strictEqual(replaceRegex(source,
|
|
48
|
+
assert.strictEqual(replaceRegex(source, match, m => m.slice(1, m.length - 1).split(':')[1].toLocaleUpperCase()), result);
|
|
49
|
+
|
|
50
|
+
/** match: "](______)" */
|
|
51
|
+
match = /]\(.+\)/gi;
|
|
52
|
+
source = '[name:root](https://kwizcom.sharepoint.com/:fl:/g/contentstorage)';
|
|
53
|
+
result = '[name:root](https~~~~//kwizcom.sharepoint.com/~~~~fl~~~~/g/contentstorage)';
|
|
54
|
+
assert.strictEqual(replaceRegex(source, match, m => m.replace(/:/gi, "~~~~")), result);
|
|
43
55
|
});
|
package/src/helpers/strings.ts
CHANGED
|
@@ -241,7 +241,8 @@ export function normalizeHtmlSpace(html: string) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
export function replaceAll(str: string, find: string, replace: string, ignoreCase = false) {
|
|
244
|
-
|
|
244
|
+
//must call escapeRegExp on find, to make sure it works when there are protected regex characters
|
|
245
|
+
return str.replace(new RegExp(escapeRegExp(find), `g${ignoreCase ? 'i' : ''}`), replace);
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
export function capitalizeFirstLetter(str: string) {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface ITenantInfo {
|
|
2
|
+
environment: AzureEnvironment;
|
|
3
|
+
idOrName: string;
|
|
4
|
+
authorityUrl: string;
|
|
5
|
+
valid: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line no-shadow
|
|
9
|
+
export const enum AzureEnvironment {
|
|
10
|
+
Production = 0,
|
|
11
|
+
PPE = 1,
|
|
12
|
+
China = 2,
|
|
13
|
+
Germany = 3,
|
|
14
|
+
USGovernment = 4
|
|
15
|
+
}
|
|
16
|
+
/** AuthenticationModes enum values for projects that can't use enums (when isolatedModules is true) */
|
|
17
|
+
export const $AzureEnvironment = {
|
|
18
|
+
Production: 0,
|
|
19
|
+
PPE: 1,
|
|
20
|
+
China: 2,
|
|
21
|
+
Germany: 3,
|
|
22
|
+
USGovernment: 4,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// eslint-disable-next-line no-shadow
|
|
26
|
+
export const enum AuthenticationModes {
|
|
27
|
+
Certificate = "certificate",
|
|
28
|
+
clientSecret = "secret"
|
|
29
|
+
}
|
|
30
|
+
/** AuthenticationModes enum values for projects that can't use enums (when isolatedModules is true) */
|
|
31
|
+
export const $AuthenticationModes = {
|
|
32
|
+
Certificate: AuthenticationModes.Certificate,
|
|
33
|
+
clientSecret: AuthenticationModes.clientSecret,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export type AuthContextType = {
|
|
38
|
+
authenticationMode: AuthenticationModes.Certificate,
|
|
39
|
+
clientId: string,
|
|
40
|
+
privateKey: string,
|
|
41
|
+
thumbprint: string
|
|
42
|
+
} | {
|
|
43
|
+
authenticationMode: AuthenticationModes.clientSecret,
|
|
44
|
+
clientId: string,
|
|
45
|
+
clientSecret: string
|
|
46
|
+
};
|
package/src/types/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from "./auth";
|
|
1
2
|
export * from "./common.types";
|
|
2
3
|
export * from './flatted.types';
|
|
3
4
|
export * from "./globals.types";
|
|
@@ -9,4 +10,3 @@ export * from "./regex.types";
|
|
|
9
10
|
export * from "./rest.types";
|
|
10
11
|
export * from "./sharepoint.types";
|
|
11
12
|
export * from "./sharepoint.utils.types";
|
|
12
|
-
|
|
@@ -1,35 +1,7 @@
|
|
|
1
|
+
import { ITenantInfo } from "../auth";
|
|
2
|
+
|
|
1
3
|
export interface IMSALBaseRequest { scopes: string[]; }
|
|
2
4
|
export interface IMSALConfig { }
|
|
3
|
-
export interface ITenantInfo {
|
|
4
|
-
environment: AzureEnvironment;
|
|
5
|
-
idOrName: string;
|
|
6
|
-
authorityUrl: string;
|
|
7
|
-
valid: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// eslint-disable-next-line no-shadow
|
|
11
|
-
export enum AzureEnvironment {
|
|
12
|
-
/// <summary>
|
|
13
|
-
///
|
|
14
|
-
/// </summary>
|
|
15
|
-
Production = 0,
|
|
16
|
-
/// <summary>
|
|
17
|
-
///
|
|
18
|
-
/// </summary>
|
|
19
|
-
PPE = 1,
|
|
20
|
-
/// <summary>
|
|
21
|
-
///
|
|
22
|
-
/// </summary>
|
|
23
|
-
China = 2,
|
|
24
|
-
/// <summary>
|
|
25
|
-
///
|
|
26
|
-
/// </summary>
|
|
27
|
-
Germany = 3,
|
|
28
|
-
/// <summary>
|
|
29
|
-
///
|
|
30
|
-
/// </summary>
|
|
31
|
-
USGovernment = 4
|
|
32
|
-
}
|
|
33
5
|
|
|
34
6
|
export const MSALSampleLoginPopupScript = `<p id="msg">please wait...</p>
|
|
35
7
|
<script>
|
|
@@ -59,13 +31,6 @@ function finish() {
|
|
|
59
31
|
finish();
|
|
60
32
|
</script>`;
|
|
61
33
|
|
|
62
|
-
export function GetTokenAudiencePrefix(appId: string) {
|
|
63
|
-
return `api://${appId}`;
|
|
64
|
-
}
|
|
65
|
-
export function GetDefaultScope(appId: string) {
|
|
66
|
-
return `${GetTokenAudiencePrefix(appId)}/access_as_user`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
34
|
export interface IMSAL {
|
|
70
35
|
AutoDiscoverTenantInfo: () => Promise<ITenantInfo>;
|
|
71
36
|
GetConfig: (clientId: string, authority: string, redirectUri: string) => Promise<IMSALConfig>;
|
|
@@ -76,4 +41,4 @@ declare global {
|
|
|
76
41
|
interface IKWizComGlobalsLibs {
|
|
77
42
|
msal?: IMSAL;
|
|
78
43
|
}
|
|
79
|
-
}
|
|
44
|
+
}
|
package/src/types/rest.types.ts
CHANGED
|
@@ -44,6 +44,8 @@ export interface IRestRequestOptions {
|
|
|
44
44
|
[key: string]: string;
|
|
45
45
|
Accept?: string;
|
|
46
46
|
"content-type"?: string;
|
|
47
|
+
/** `Bearer ${token}` */
|
|
48
|
+
Authorization?: string;
|
|
47
49
|
};
|
|
48
50
|
/** allow cache on post requests if you provide a unique key to identify and match */
|
|
49
51
|
postCacheKey?: string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function GetTokenAudiencePrefix(appId: string) {
|
|
2
|
+
return `api://${appId}`;
|
|
3
|
+
}
|
|
4
|
+
export function GetDefaultScope(appId: string) {
|
|
5
|
+
return `${GetTokenAudiencePrefix(appId)}/access_as_user`;
|
|
6
|
+
}
|
|
7
|
+
export function GetMSALSiteScope(siteUrl: string) {
|
|
8
|
+
return `https://${new URL(siteUrl).hostname}`;
|
|
9
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { AzureEnvironment, ITenantInfo, isNullOrEmptyString, isValidGuid, promiseOnce } from "../_dependencies";
|
|
2
|
+
import { GetJson } from "../rest";
|
|
3
|
+
|
|
4
|
+
export function DiscoverTenantInfo(hostName: string) {
|
|
5
|
+
hostName = hostName.toLowerCase();
|
|
6
|
+
return promiseOnce(`DiscoverTenantInfo|${hostName}`, async () => {
|
|
7
|
+
let data: ITenantInfo = {
|
|
8
|
+
environment: AzureEnvironment.Production,
|
|
9
|
+
idOrName: null,
|
|
10
|
+
authorityUrl: null,
|
|
11
|
+
valid: false
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let tenantId: string = null;
|
|
15
|
+
let friendlyName: string = null;
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
if (hostName.indexOf(".sharepoint.") !== -1) {
|
|
19
|
+
let hostParts = hostName.split('.');//should be xxx.sharepoint.com or xxx.sharepoint.us
|
|
20
|
+
let firstHostPart = hostParts[0];
|
|
21
|
+
let lastHostPart = hostParts[hostParts.length - 1] === "us" || hostParts[hostParts.length - 1] === "de" ? hostParts[hostParts.length - 1] : "com";
|
|
22
|
+
if (firstHostPart.endsWith("-admin")) firstHostPart = firstHostPart.substring(0, firstHostPart.length - 6);
|
|
23
|
+
friendlyName = `${firstHostPart}.onmicrosoft.${lastHostPart}`;
|
|
24
|
+
}
|
|
25
|
+
else friendlyName = hostName;//could be an exchange email domain, or bpos customer
|
|
26
|
+
|
|
27
|
+
let config = await GetJson<{
|
|
28
|
+
token_endpoint: string;//https://login.microsoftonline.com/7d034656-be03-457d-8d82-60e90cf5f400/oauth2/token
|
|
29
|
+
cloud_instance_name: string;//microsoftonline.com
|
|
30
|
+
token_endpoint_auth_methods_supported: string[];// ["client_secret_post", "private_key_jwt", "client_secret_basic"]
|
|
31
|
+
response_modes_supported: string[];// ["query", "fragment", "form_post"]
|
|
32
|
+
response_types_supported: string[];// ["code", "id_token", "code id_token", "token id_token", "token"]
|
|
33
|
+
scopes_supported: string[];// ["openid"]
|
|
34
|
+
issuer: string;//https://sts.windows.net/7d034656-be03-457d-8d82-60e90cf5f400/
|
|
35
|
+
authorization_endpoint: string;//https://login.microsoftonline.com/7d034656-be03-457d-8d82-60e90cf5f400/oauth2/authorize
|
|
36
|
+
device_authorization_endpoint: string;//https://login.microsoftonline.com/7d034656-be03-457d-8d82-60e90cf5f400/oauth2/devicecode
|
|
37
|
+
end_session_endpoint: string;//https://login.microsoftonline.com/7d034656-be03-457d-8d82-60e90cf5f400/oauth2/logout
|
|
38
|
+
userinfo_endpoint: string;//https://login.microsoftonline.com/7d034656-be03-457d-8d82-60e90cf5f400/openid/userinfo
|
|
39
|
+
tenant_region_scope: string;//NA
|
|
40
|
+
cloud_graph_host_name: string;//graph.windows.net
|
|
41
|
+
msgraph_host: string;//graph.microsoft.com
|
|
42
|
+
}>(`https://login.microsoftonline.com/${friendlyName}/v2.0/.well-known/openid-configuration`);
|
|
43
|
+
|
|
44
|
+
let endpoint = config.token_endpoint;//https://xxxx/{tenant}/....
|
|
45
|
+
tenantId = endpoint.replace("//", "/").split('/')[2];//replace :// with :/ split by / and take the second part.
|
|
46
|
+
let instance = config.cloud_instance_name;//microsoftonline.us
|
|
47
|
+
|
|
48
|
+
data.environment = GetEnvironmentFromACSEndPoint(instance);
|
|
49
|
+
if (!isNullOrEmptyString(tenantId) || isValidGuid(tenantId))
|
|
50
|
+
data.idOrName = tenantId;
|
|
51
|
+
else
|
|
52
|
+
data.idOrName = friendlyName;
|
|
53
|
+
|
|
54
|
+
data.authorityUrl = `${GetAzureADLoginEndPoint(data.environment)}/${data.idOrName}`;
|
|
55
|
+
data.valid = true;
|
|
56
|
+
}
|
|
57
|
+
catch (e) { }
|
|
58
|
+
|
|
59
|
+
return data;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function AutoDiscoverTenantInfo() {
|
|
64
|
+
return DiscoverTenantInfo(window.location.hostname.toLowerCase());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function GetEnvironmentFromACSEndPoint(ACSEndPoint: string): AzureEnvironment {
|
|
68
|
+
switch (ACSEndPoint) {
|
|
69
|
+
case "microsoftonline.us":
|
|
70
|
+
return AzureEnvironment.USGovernment;
|
|
71
|
+
case "microsoftonline.de":
|
|
72
|
+
return AzureEnvironment.Germany;
|
|
73
|
+
case "accesscontrol.chinacloudapi.cn":
|
|
74
|
+
return AzureEnvironment.China;
|
|
75
|
+
case "windows-ppe.net":
|
|
76
|
+
return AzureEnvironment.PPE;
|
|
77
|
+
case "accesscontrol.windows.net":
|
|
78
|
+
default:
|
|
79
|
+
return AzureEnvironment.Production;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function GetAzureADLoginEndPoint(environment: AzureEnvironment): string {
|
|
83
|
+
switch (environment) {
|
|
84
|
+
case AzureEnvironment.Germany: return "https://login.microsoftonline.de";
|
|
85
|
+
case AzureEnvironment.China: return "https://login.chinacloudapi.cn";
|
|
86
|
+
case AzureEnvironment.USGovernment: return "https://login.microsoftonline.us";
|
|
87
|
+
case AzureEnvironment.PPE: return "https://login.windows-ppe.net";
|
|
88
|
+
case AzureEnvironment.Production:
|
|
89
|
+
default:
|
|
90
|
+
return "https://login.microsoftonline.com";
|
|
91
|
+
}
|
|
92
|
+
}
|