@adobe/helix-onedrive-support 7.1.4 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +33 -0
- package/.husky/pre-commit +4 -0
- package/.jsdoc.json +4 -2
- package/.nycrc.json +4 -3
- package/.releaserc.cjs +16 -0
- package/CHANGELOG.md +21 -0
- package/docs/API.md +106 -341
- package/package.json +17 -17
- package/src/OneDrive.d.ts +4 -72
- package/src/OneDrive.js +62 -326
- package/src/OneDriveAuth.d.ts +98 -0
- package/src/OneDriveAuth.js +310 -0
- package/src/OneDriveMock.js +19 -12
- package/src/SharePointSite.js +5 -7
- package/src/StatusCodeError.js +2 -4
- package/src/cache/FSCacheManager.d.ts +28 -0
- package/src/cache/FSCacheManager.js +77 -0
- package/src/cache/FSCachePlugin.d.ts +29 -0
- package/src/cache/FSCachePlugin.js +70 -0
- package/src/cache/MemCachePlugin.d.ts +34 -0
- package/src/cache/MemCachePlugin.js +88 -0
- package/src/cache/S3CacheManager.d.ts +40 -0
- package/src/cache/S3CacheManager.js +107 -0
- package/src/cache/S3CachePlugin.d.ts +49 -0
- package/src/cache/S3CachePlugin.js +116 -0
- package/src/cache/encrypt.js +70 -0
- package/src/{NamedItem.d.ts → excel/NamedItem.d.ts} +0 -0
- package/src/{NamedItemContainer.js → excel/NamedItemContainer.js} +3 -5
- package/src/{Range.d.ts → excel/Range.d.ts} +2 -2
- package/src/{Range.js → excel/Range.js} +3 -5
- package/src/{Table.d.ts → excel/Table.d.ts} +2 -2
- package/src/{Table.js → excel/Table.js} +3 -5
- package/src/{Workbook.d.ts → excel/Workbook.d.ts} +2 -2
- package/src/{Workbook.js → excel/Workbook.js} +5 -10
- package/src/{Worksheet.d.ts → excel/Worksheet.d.ts} +4 -4
- package/src/{Worksheet.js → excel/Worksheet.js} +5 -10
- package/src/index.d.ts +14 -5
- package/src/index.js +9 -7
- package/src/package.cjs +12 -0
- package/src/utils.js +95 -45
- package/src/fuzzy-helper.js +0 -89
package/package.json
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/helix-onedrive-support",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Helix OneDrive Support",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.js",
|
|
8
|
+
"./utils": "./src/utils.js"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
6
11
|
"types": "src/index.d.ts",
|
|
7
12
|
"scripts": {
|
|
8
|
-
"test": "
|
|
9
|
-
"test-ci": "
|
|
13
|
+
"test": "c8 mocha",
|
|
14
|
+
"test-ci": "c8 mocha && codecov",
|
|
10
15
|
"lint": "./node_modules/.bin/eslint .",
|
|
11
16
|
"semantic-release": "semantic-release",
|
|
12
17
|
"docs": "npx jsdoc2md -c .jsdoc.json --files 'src/*.js' > docs/API.md",
|
|
13
|
-
"
|
|
18
|
+
"prepare": "husky install"
|
|
14
19
|
},
|
|
15
20
|
"repository": {
|
|
16
21
|
"type": "git",
|
|
@@ -24,7 +29,8 @@
|
|
|
24
29
|
"homepage": "https://github.com/adobe/helix-onedrive-support#readme",
|
|
25
30
|
"dependencies": {
|
|
26
31
|
"@adobe/helix-fetch": "3.0.9",
|
|
27
|
-
"
|
|
32
|
+
"@aws-sdk/client-s3": "3.56.0",
|
|
33
|
+
"@azure/msal-node": "1.7.0",
|
|
28
34
|
"jose": "4.8.0"
|
|
29
35
|
},
|
|
30
36
|
"devDependencies": {
|
|
@@ -32,33 +38,27 @@
|
|
|
32
38
|
"@semantic-release/changelog": "6.0.1",
|
|
33
39
|
"@semantic-release/git": "10.0.1",
|
|
34
40
|
"ajv": "8.11.0",
|
|
41
|
+
"c8": "7.11.0",
|
|
35
42
|
"codecov": "3.8.3",
|
|
36
|
-
"commitizen": "4.2.4",
|
|
37
|
-
"cz-conventional-changelog": "3.3.0",
|
|
38
43
|
"dotenv": "16.0.0",
|
|
39
44
|
"eslint": "8.14.0",
|
|
40
45
|
"eslint-plugin-header": "3.1.1",
|
|
41
46
|
"eslint-plugin-import": "2.26.0",
|
|
47
|
+
"husky": "7.0.4",
|
|
48
|
+
"install": "0.13.0",
|
|
42
49
|
"jsdoc-to-markdown": "7.1.1",
|
|
50
|
+
"jsdoc-tsimport-plugin": "1.0.5",
|
|
43
51
|
"junit-report-builder": "3.0.0",
|
|
44
52
|
"lint-staged": "12.4.1",
|
|
45
|
-
"mocha": "
|
|
53
|
+
"mocha": "10.0.0",
|
|
46
54
|
"mocha-multi-reporters": "1.5.1",
|
|
47
55
|
"nock": "13.2.4",
|
|
48
|
-
"
|
|
56
|
+
"npm": "8.8.0",
|
|
49
57
|
"semantic-release": "19.0.2"
|
|
50
58
|
},
|
|
51
59
|
"lint-staged": {
|
|
52
60
|
"*.js": "eslint"
|
|
53
61
|
},
|
|
54
|
-
"config": {
|
|
55
|
-
"commitizen": {
|
|
56
|
-
"path": "node_modules/cz-conventional-changelog"
|
|
57
|
-
},
|
|
58
|
-
"ghooks": {
|
|
59
|
-
"pre-commit": "npx lint-staged"
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
62
|
"mocha": {
|
|
63
63
|
"spec": "test/**/*.test.js",
|
|
64
64
|
"require": "test/setup-env.js",
|
package/src/OneDrive.d.ts
CHANGED
|
@@ -10,29 +10,13 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
import { EventEmitter } from 'events';
|
|
13
|
-
import { Workbook } from './Workbook';
|
|
13
|
+
import { Workbook } from './excel/Workbook';
|
|
14
14
|
import { TokenResponse } from 'adal-node';
|
|
15
|
+
import {OneDriveAuth} from "./OneDriveAuth";
|
|
15
16
|
|
|
16
|
-
/**
|
|
17
|
-
* Logger interface
|
|
18
|
-
*/
|
|
19
|
-
declare interface Logger {
|
|
20
|
-
}
|
|
21
17
|
|
|
22
18
|
export declare interface OneDriveOptions {
|
|
23
|
-
|
|
24
|
-
clientSecret?: string;
|
|
25
|
-
refreshToken?: string;
|
|
26
|
-
log?: Logger;
|
|
27
|
-
tenant?: string;
|
|
28
|
-
resource?: string;
|
|
29
|
-
username?: string;
|
|
30
|
-
password?: string;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Uses a local auth cache for access tokens.
|
|
34
|
-
*/
|
|
35
|
-
localAuthCache?: boolean,
|
|
19
|
+
auth: OneDriveAuth;
|
|
36
20
|
|
|
37
21
|
/**
|
|
38
22
|
* Disables the cache for the share link lookup.
|
|
@@ -45,18 +29,6 @@ export declare interface OneDriveOptions {
|
|
|
45
29
|
* Note that the cache is only used, if the `noShareLinkCache` flag is `falsy`
|
|
46
30
|
*/
|
|
47
31
|
shareLinkCache?: Map<string, DriveItem>,
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Disables the cache for the tenant lookup.
|
|
51
|
-
* @default process.env.HELIX_ONEDRIVE_NO_TENANT_CACHE
|
|
52
|
-
*/
|
|
53
|
-
noTenantCache?: boolean;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Map to use for the tenant lookup cache. If empty, a module-global cache will be used.
|
|
57
|
-
* Note that the cache is only used, if the `noTenantCache` flag is `falsy`
|
|
58
|
-
*/
|
|
59
|
-
tenantCache?: Map<string, DriveItem>,
|
|
60
32
|
}
|
|
61
33
|
|
|
62
34
|
export declare interface GraphResult {
|
|
@@ -145,57 +117,17 @@ export declare class OneDrive extends EventEmitter {
|
|
|
145
117
|
*/
|
|
146
118
|
constructor(opts: OneDriveOptions);
|
|
147
119
|
|
|
148
|
-
/**
|
|
149
|
-
* is set to {@code true} if this client is initialized.
|
|
150
|
-
*/
|
|
151
|
-
authenticated: boolean;
|
|
152
|
-
|
|
153
120
|
/**
|
|
154
121
|
* the logger of this client
|
|
155
122
|
*/
|
|
156
123
|
log: Logger;
|
|
157
124
|
|
|
158
|
-
|
|
159
|
-
* the authority url for login.
|
|
160
|
-
*/
|
|
161
|
-
getAuthorityUrl(): string;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Adds entries to the token cache
|
|
165
|
-
* @param {TokenResponse[]} entries
|
|
166
|
-
*/
|
|
167
|
-
loadTokenCache(entries: TokenResponse[]): Promise<void>;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Performs a login using an interactive flow which prompts the user to open a browser window and
|
|
171
|
-
* enter the authorization code.
|
|
172
|
-
* @params {function} [onCode] - optional function that gets invoked after code was retrieved.
|
|
173
|
-
* @returns {Promise<TokenResponse>}
|
|
174
|
-
*/
|
|
175
|
-
login(onCode: Function): Promise<TokenResponse>;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Sets the access token to use for all requests. if the token is a valid JWT token,
|
|
179
|
-
* its `tid` claim is used a tenant (if no tenant is already set).
|
|
180
|
-
*
|
|
181
|
-
* @param {string} bearerToken
|
|
182
|
-
*/
|
|
183
|
-
setAccessToken(bearerToken);
|
|
184
|
-
|
|
185
|
-
getAccessToken(autoRefresh: boolean): Promise<TokenResponse>;
|
|
186
|
-
|
|
187
|
-
createLoginUrl(): string;
|
|
188
|
-
|
|
189
|
-
acquireToken(redirectUri: string, code: string): Promise<TokenResponse>;
|
|
125
|
+
auth: OneDriveAuth;
|
|
190
126
|
|
|
191
127
|
dispose() : Promise<void>;
|
|
192
128
|
|
|
193
|
-
doFetch(relUrl: string, rawResponseBody: boolean = false, options: object = {}): Promise<object|Buffer>
|
|
194
|
-
|
|
195
129
|
me(): Promise<GraphResult>;
|
|
196
130
|
|
|
197
|
-
initTenantFromShareLink(sharingUrl: string|URL): Promise<void>;
|
|
198
|
-
|
|
199
131
|
resolveShareLink(sharingUrl: string|URL): Promise<GraphResult>;
|
|
200
132
|
|
|
201
133
|
/**
|
package/src/OneDrive.js
CHANGED
|
@@ -11,22 +11,13 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
// eslint-disable-next-line max-classes-per-file
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const Workbook = require('./Workbook.js');
|
|
21
|
-
const StatusCodeError = require('./StatusCodeError.js');
|
|
22
|
-
const { driveItemFromURL, driveItemToURL } = require('./utils.js');
|
|
23
|
-
const { splitByExtension, sanitize, editDistance } = require('./fuzzy-helper.js');
|
|
24
|
-
const SharePointSite = require('./SharePointSite.js');
|
|
25
|
-
|
|
26
|
-
const AZ_AUTHORITY_HOST_URL = 'https://login.windows.net';
|
|
27
|
-
const AZ_DEFAULT_RESOURCE = 'https://graph.microsoft.com'; // '00000002-0000-0000-c000-000000000000'; ??
|
|
28
|
-
const AZ_COMMON_TENANT = 'common';
|
|
14
|
+
import { keepAliveNoCache } from '@adobe/helix-fetch';
|
|
15
|
+
import { Workbook } from './excel/Workbook.js';
|
|
16
|
+
import { StatusCodeError } from './StatusCodeError.js';
|
|
17
|
+
import { editDistance, sanitizeName, splitByExtension } from './utils.js';
|
|
18
|
+
import { SharePointSite } from './SharePointSite.js';
|
|
29
19
|
|
|
20
|
+
const { fetch, reset } = keepAliveNoCache({ userAgent: 'helix-fetch' });
|
|
30
21
|
/**
|
|
31
22
|
* the maximum subscription time in milliseconds
|
|
32
23
|
* @see https://docs.microsoft.com/en-us/graph/api/resources/subscription?view=graph-rest-1.0#maximum-length-of-subscription-per-resource-type
|
|
@@ -43,144 +34,76 @@ const MAX_SUBSCRIPTION_EXPIRATION_TIME = 4230 * 60 * 1000;
|
|
|
43
34
|
*/
|
|
44
35
|
const globalShareLinkCache = new Map();
|
|
45
36
|
|
|
46
|
-
/**
|
|
47
|
-
* map that caches the tenant ids
|
|
48
|
-
* @type {Map<string, string>}
|
|
49
|
-
*/
|
|
50
|
-
const globalTenantCache = new Map();
|
|
51
|
-
|
|
52
37
|
/**
|
|
53
38
|
* Helper class that facilitates accessing one drive.
|
|
39
|
+
*
|
|
40
|
+
* @class
|
|
41
|
+
* @field {ConfidentialClientApplication|PublicClientApplication} app
|
|
54
42
|
*/
|
|
55
|
-
class OneDrive
|
|
43
|
+
export class OneDrive {
|
|
56
44
|
/**
|
|
57
|
-
*
|
|
45
|
+
* Returns an onedrive uri for the given drive item. the uri has the format:
|
|
46
|
+
* `onedrive:/drives/<driveId>/items/<itemId>`
|
|
47
|
+
*
|
|
48
|
+
* @param {DriveItem} driveItem
|
|
49
|
+
* @returns {URL} An url representing the drive item
|
|
58
50
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.clientId = opts.clientId;
|
|
62
|
-
this.clientSecret = opts.clientSecret || '';
|
|
63
|
-
this.refreshToken = opts.refreshToken || '';
|
|
64
|
-
this.username = opts.username || '';
|
|
65
|
-
this.password = opts.password || '';
|
|
66
|
-
this._log = opts.log || console;
|
|
67
|
-
this.tenant = opts.tenant;
|
|
68
|
-
this.resource = opts.resource || AZ_DEFAULT_RESOURCE;
|
|
69
|
-
this.localAuthCache = opts.localAuthCache;
|
|
70
|
-
|
|
71
|
-
if (!opts.noShareLinkCache && !process.env.HELIX_ONEDRIVE_NO_SHARE_LINK_CACHE) {
|
|
72
|
-
/** @type {Map<string, string>} */
|
|
73
|
-
this.shareLinkCache = opts.shareLinkCache || globalShareLinkCache;
|
|
74
|
-
}
|
|
75
|
-
if (!opts.noTenantCache && !process.env.HELIX_ONEDRIVE_NO_TENANT_CACHE) {
|
|
76
|
-
/** @type {Map<string, string>} */
|
|
77
|
-
this.tenantCache = opts.tenantCache || globalTenantCache;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (!this.clientId) {
|
|
81
|
-
throw new Error('Missing clientId.');
|
|
82
|
-
}
|
|
51
|
+
static driveItemToURL(driveItem) {
|
|
52
|
+
return new URL(`onedrive:/drives/${driveItem.parentReference.driveId}/items/${driveItem.id}`);
|
|
83
53
|
}
|
|
84
54
|
|
|
85
55
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
56
|
+
* Returns a partial drive item from the given url. The urls needs to have the format:
|
|
57
|
+
* `onedrive:/drives/<driveId>/items/<itemId>`. if the url does not start with the correct
|
|
58
|
+
* protocol, {@code null} is returned.
|
|
59
|
+
*
|
|
60
|
+
* @param {URL|string} url The url of the drive item.
|
|
61
|
+
* @return {DriveItem} A (partial) drive item.
|
|
88
62
|
*/
|
|
89
|
-
|
|
90
|
-
if (!
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
undefined,
|
|
94
|
-
this.localAuthCache ? new MemoryCache() : undefined,
|
|
95
|
-
);
|
|
96
|
-
[
|
|
97
|
-
'acquireUserCode',
|
|
98
|
-
'acquireToken',
|
|
99
|
-
'acquireTokenWithDeviceCode',
|
|
100
|
-
'acquireTokenWithRefreshToken',
|
|
101
|
-
'acquireTokenWithUsernamePassword',
|
|
102
|
-
'acquireTokenWithClientCredentials',
|
|
103
|
-
].forEach((m) => {
|
|
104
|
-
this.authContext[m] = promisify(this.authContext[m].bind(this.authContext));
|
|
105
|
-
});
|
|
106
|
-
const { cache } = this.authContext;
|
|
107
|
-
if (this.localAuthCache) {
|
|
108
|
-
const originalAdd = cache.add;
|
|
109
|
-
cache.add = (entries, cb) => {
|
|
110
|
-
originalAdd.call(cache, entries, (...args) => {
|
|
111
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
112
|
-
this.emit('tokens', cache._entries);
|
|
113
|
-
cb(...args);
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
const originalRemove = cache.remove;
|
|
117
|
-
cache.remove = (entries, cb) => {
|
|
118
|
-
originalRemove.call(cache, entries, (...args) => {
|
|
119
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
120
|
-
this.emit('tokens', cache._entries);
|
|
121
|
-
cb(...args);
|
|
122
|
-
});
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
cache.add.promise = promisify(cache.add.bind(cache));
|
|
126
|
-
cache.remove.promise = promisify(cache.remove.bind(cache));
|
|
127
|
-
cache.find.promise = promisify(cache.find.bind(cache));
|
|
63
|
+
static driveItemFromURL(url) {
|
|
64
|
+
if (!(url instanceof URL)) {
|
|
65
|
+
// eslint-disable-next-line no-param-reassign
|
|
66
|
+
url = new URL(String(url));
|
|
128
67
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
async resolveTenant(tenantHost) {
|
|
133
|
-
const { log } = this;
|
|
134
|
-
const configUrl = `https://login.windows.net/${tenantHost}.onmicrosoft.com/.well-known/openid-configuration`;
|
|
135
|
-
const res = await fetch(configUrl);
|
|
136
|
-
if (!res.ok) {
|
|
137
|
-
log.info(`error fetching openid-configuration for ${tenantHost}: ${res.status}. Fallback to 'common'`);
|
|
138
|
-
return AZ_COMMON_TENANT;
|
|
68
|
+
if (url.protocol !== 'onedrive:') {
|
|
69
|
+
return null;
|
|
139
70
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
log.info(`unable to extract tenant from openid-configuration for ${tenantHost}: no 'issuer'. Fallback to 'common'`);
|
|
144
|
-
return AZ_COMMON_TENANT;
|
|
71
|
+
const [drives, driveId, items, itemId] = url.pathname.split('/').filter((s) => !!s);
|
|
72
|
+
if (drives !== 'drives') {
|
|
73
|
+
throw new Error(`URI not supported (missing 'drives' segment): ${url}`);
|
|
145
74
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
75
|
+
if (items !== 'items') {
|
|
76
|
+
throw new Error(`URI not supported (missing 'items' segment): ${url}`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
id: itemId,
|
|
80
|
+
parentReference: {
|
|
81
|
+
driveId,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
151
84
|
}
|
|
152
85
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
? sharingUrl
|
|
160
|
-
: new URL(sharingUrl);
|
|
161
|
-
let [tenantHost] = url.hostname.split('.');
|
|
162
|
-
// special case: `xxxx-my.sharepoint.com`
|
|
163
|
-
if (url.hostname.endsWith('-my.sharepoint.com')) {
|
|
164
|
-
tenantHost = tenantHost.substring(0, tenantHost.length - 3);
|
|
86
|
+
/**
|
|
87
|
+
* @param {OneDriveOptions} opts Options
|
|
88
|
+
*/
|
|
89
|
+
constructor(opts) {
|
|
90
|
+
if (!opts.auth) {
|
|
91
|
+
throw new Error('Missing auth.');
|
|
165
92
|
}
|
|
93
|
+
this.auth = opts.auth;
|
|
94
|
+
this._log = opts.auth.log;
|
|
166
95
|
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (!this.tenant) {
|
|
171
|
-
this.tenant = await this.resolveTenant(tenantHost);
|
|
172
|
-
if (this.tenantCache) {
|
|
173
|
-
this.tenantCache.set(tenantHost, this.tenant);
|
|
174
|
-
}
|
|
96
|
+
if (!opts.noShareLinkCache && !process.env.HELIX_ONEDRIVE_NO_SHARE_LINK_CACHE) {
|
|
97
|
+
/** @type {Map<string, string>} */
|
|
98
|
+
this.shareLinkCache = opts.shareLinkCache || globalShareLinkCache;
|
|
175
99
|
}
|
|
176
|
-
log.info(`using tenant ${this.tenant} for ${tenantHost} from ${sharingUrl}`);
|
|
177
100
|
}
|
|
178
101
|
|
|
179
102
|
/**
|
|
180
103
|
*/
|
|
181
|
-
// eslint-disable-next-line class-methods-use-this
|
|
182
104
|
async dispose() {
|
|
183
105
|
// TODO: clear other state?
|
|
106
|
+
await this.auth.dispose();
|
|
184
107
|
return reset();
|
|
185
108
|
}
|
|
186
109
|
|
|
@@ -190,194 +113,11 @@ class OneDrive extends EventEmitter {
|
|
|
190
113
|
return this._log;
|
|
191
114
|
}
|
|
192
115
|
|
|
193
|
-
getAuthorityUrl() {
|
|
194
|
-
if (!this.tenant) {
|
|
195
|
-
throw new Error('unable to compute authority url. no tenant.');
|
|
196
|
-
}
|
|
197
|
-
return `${AZ_AUTHORITY_HOST_URL}/${this.tenant}`;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* @returns {boolean}
|
|
202
|
-
*/
|
|
203
|
-
get authenticated() {
|
|
204
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
205
|
-
return this.authContext?.cache._entries.length > 0;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Adds entries to the token cache
|
|
210
|
-
* @param {TokenResponse[]} entries
|
|
211
|
-
* @return this;
|
|
212
|
-
*/
|
|
213
|
-
async loadTokenCache(entries) {
|
|
214
|
-
return (await this.getAuthContext()).cache.add.promise(entries);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Performs a login using an interactive flow which prompts the user to open a browser window and
|
|
219
|
-
* enter the authorization code.
|
|
220
|
-
* @params {function} [onCode] - optional function that gets invoked after code was retrieved.
|
|
221
|
-
* @returns {Promise<TokenResponse>}
|
|
222
|
-
*/
|
|
223
|
-
async login(onCode) {
|
|
224
|
-
const { log } = this;
|
|
225
|
-
const context = await this.getAuthContext();
|
|
226
|
-
|
|
227
|
-
let code;
|
|
228
|
-
try {
|
|
229
|
-
code = await context.acquireUserCode(this.resource, this.clientId, 'en');
|
|
230
|
-
} catch (e) {
|
|
231
|
-
log.error('Error while requesting user code', e);
|
|
232
|
-
throw e;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
log.info(code.message);
|
|
236
|
-
if (typeof onCode === 'function') {
|
|
237
|
-
await onCode(code);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
return await context.acquireTokenWithDeviceCode(this.resource, this.clientId, code);
|
|
242
|
-
} catch (e) {
|
|
243
|
-
log.error('Error while requesting access token with device code', e);
|
|
244
|
-
throw e;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Sets the access token to use for all requests. if the token is a valid JWT token,
|
|
250
|
-
* its `tid` claim is used a tenant (if no tenant is already set).
|
|
251
|
-
*
|
|
252
|
-
* @param {string} bearerToken
|
|
253
|
-
*/
|
|
254
|
-
setAccessToken(bearerToken) {
|
|
255
|
-
const { log } = this;
|
|
256
|
-
this.accessToken = {
|
|
257
|
-
accessToken: bearerToken,
|
|
258
|
-
};
|
|
259
|
-
if (!this.tenant) {
|
|
260
|
-
try {
|
|
261
|
-
const { tid } = jose.decodeJwt(bearerToken);
|
|
262
|
-
if (tid) {
|
|
263
|
-
log.info(`using tenant from access token: ${tid}`);
|
|
264
|
-
this.tenant = tid;
|
|
265
|
-
}
|
|
266
|
-
} catch (e) {
|
|
267
|
-
log.warn(`unable to decode access token: ${e.message}`);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
this.accessToken.tenantId = this.tenant;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
*/
|
|
275
|
-
async fetchAccessToken() {
|
|
276
|
-
const { log } = this;
|
|
277
|
-
const context = await this.getAuthContext();
|
|
278
|
-
try {
|
|
279
|
-
return await context.acquireToken(this.resource, this.username, this.clientId);
|
|
280
|
-
} catch (e) {
|
|
281
|
-
if (e.message !== 'Entry not found in cache.') {
|
|
282
|
-
log.warn(`Unable to acquire token from cache: ${e}`);
|
|
283
|
-
} else {
|
|
284
|
-
log.debug(`Unable to acquire token from cache: ${e}`);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
try {
|
|
289
|
-
if (this.refreshToken) {
|
|
290
|
-
log.debug('acquire token with refresh token.');
|
|
291
|
-
const resp = await context.acquireTokenWithRefreshToken(
|
|
292
|
-
this.refreshToken,
|
|
293
|
-
this.clientId,
|
|
294
|
-
this.clientSecret,
|
|
295
|
-
this.resource,
|
|
296
|
-
);
|
|
297
|
-
return await this.augmentAndCacheResponse(resp);
|
|
298
|
-
} else if (this.username && this.password) {
|
|
299
|
-
log.debug('acquire token with ROPC.');
|
|
300
|
-
return await context.acquireTokenWithUsernamePassword(
|
|
301
|
-
this.resource,
|
|
302
|
-
this.username,
|
|
303
|
-
this.password,
|
|
304
|
-
this.clientId,
|
|
305
|
-
);
|
|
306
|
-
} else if (this.clientSecret) {
|
|
307
|
-
log.debug('acquire token with client credentials.');
|
|
308
|
-
return await context.acquireTokenWithClientCredentials(
|
|
309
|
-
this.resource,
|
|
310
|
-
this.clientId,
|
|
311
|
-
this.clientSecret,
|
|
312
|
-
);
|
|
313
|
-
} else {
|
|
314
|
-
const err = new StatusCodeError('No valid authentication credentials supplied.');
|
|
315
|
-
err.statusCode = 401;
|
|
316
|
-
throw err;
|
|
317
|
-
}
|
|
318
|
-
} catch (e) {
|
|
319
|
-
log.error(`Error while refreshing access token ${e}`);
|
|
320
|
-
throw e;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
async getAccessToken() {
|
|
325
|
-
if (!this.accessToken) {
|
|
326
|
-
this.accessToken = await this.fetchAccessToken();
|
|
327
|
-
}
|
|
328
|
-
return this.accessToken;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
*/
|
|
333
|
-
createLoginUrl(redirectUri, state) {
|
|
334
|
-
return `${this.getAuthorityUrl()}/oauth2/authorize?response_type=code&scope=/.default&client_id=${this.clientId}&redirect_uri=${redirectUri}&state=${state}&resource=${this.resource}`;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
async augmentAndCacheResponse(response) {
|
|
338
|
-
// somehow adal doesn't add the clientId and authority to response
|
|
339
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
340
|
-
if (!response._clientId) {
|
|
341
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
342
|
-
response._clientId = this.clientId;
|
|
343
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
344
|
-
response._authority = this.authorityUrl;
|
|
345
|
-
}
|
|
346
|
-
const found = await this.authContext.cache.find.promise({
|
|
347
|
-
refreshToken: response.refreshToken,
|
|
348
|
-
});
|
|
349
|
-
if (found.length) {
|
|
350
|
-
await this.authContext.cache.remove.promise(found);
|
|
351
|
-
}
|
|
352
|
-
await this.authContext.cache.add.promise([response]);
|
|
353
|
-
return response;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
*/
|
|
358
|
-
async acquireToken(redirectUri, code) {
|
|
359
|
-
const { log } = this;
|
|
360
|
-
const context = await this.getAuthContext();
|
|
361
|
-
try {
|
|
362
|
-
const resp = await context.acquireTokenWithAuthorizationCode(
|
|
363
|
-
code,
|
|
364
|
-
redirectUri,
|
|
365
|
-
this.resource,
|
|
366
|
-
this.clientId,
|
|
367
|
-
this.clientSecret,
|
|
368
|
-
);
|
|
369
|
-
return await this.augmentAndCacheResponse(resp);
|
|
370
|
-
} catch (e) {
|
|
371
|
-
log.error('Error while getting token with authorization code.', e);
|
|
372
|
-
throw e;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
116
|
/**
|
|
377
117
|
*/
|
|
378
118
|
async doFetch(relUrl, rawResponseBody = false, options = {}) {
|
|
379
119
|
const opts = { ...options };
|
|
380
|
-
const { accessToken } = await this.
|
|
120
|
+
const { accessToken } = await this.auth.authenticate();
|
|
381
121
|
if (!opts.headers) {
|
|
382
122
|
opts.headers = {};
|
|
383
123
|
}
|
|
@@ -440,7 +180,7 @@ class OneDrive extends EventEmitter {
|
|
|
440
180
|
/**
|
|
441
181
|
*/
|
|
442
182
|
async resolveShareLink(sharingUrl) {
|
|
443
|
-
await this.
|
|
183
|
+
await this.auth.initTenantFromUrl(sharingUrl);
|
|
444
184
|
const link = OneDrive.encodeSharingUrl(sharingUrl);
|
|
445
185
|
this.log.debug(`resolving sharelink ${sharingUrl} (${link})`);
|
|
446
186
|
try {
|
|
@@ -467,7 +207,7 @@ class OneDrive extends EventEmitter {
|
|
|
467
207
|
if (driveItem) {
|
|
468
208
|
return driveItem;
|
|
469
209
|
}
|
|
470
|
-
await this.
|
|
210
|
+
await this.auth.initTenantFromUrl(sharingUrl);
|
|
471
211
|
if (this.shareLinkCache) {
|
|
472
212
|
driveItem = this.shareLinkCache.get(sharingUrl);
|
|
473
213
|
}
|
|
@@ -538,7 +278,7 @@ class OneDrive extends EventEmitter {
|
|
|
538
278
|
const folderRelPath = relPath.substring(0, idx);
|
|
539
279
|
const name = relPath.substring(idx + 1);
|
|
540
280
|
const [baseName, ext] = splitByExtension(name);
|
|
541
|
-
const sanitizedName =
|
|
281
|
+
const sanitizedName = sanitizeName(baseName);
|
|
542
282
|
|
|
543
283
|
const query = {
|
|
544
284
|
$top: 999,
|
|
@@ -571,7 +311,7 @@ class OneDrive extends EventEmitter {
|
|
|
571
311
|
// only match extension if given via relPath
|
|
572
312
|
return false;
|
|
573
313
|
}
|
|
574
|
-
const sanitizedItemName =
|
|
314
|
+
const sanitizedItemName = sanitizeName(itemName);
|
|
575
315
|
if (sanitizedItemName !== sanitizedName) {
|
|
576
316
|
return false;
|
|
577
317
|
}
|
|
@@ -746,14 +486,14 @@ class OneDrive extends EventEmitter {
|
|
|
746
486
|
const [, owner, site, root] = match;
|
|
747
487
|
|
|
748
488
|
try {
|
|
749
|
-
const
|
|
489
|
+
const authResult = await this.auth.authenticate();
|
|
750
490
|
return new SharePointSite({
|
|
751
491
|
owner,
|
|
752
492
|
site,
|
|
753
493
|
root,
|
|
754
494
|
clientId: this.clientId,
|
|
755
|
-
tenantId:
|
|
756
|
-
refreshToken:
|
|
495
|
+
tenantId: authResult.tenantId,
|
|
496
|
+
refreshToken: authResult.refreshToken,
|
|
757
497
|
log: this.log,
|
|
758
498
|
});
|
|
759
499
|
} catch (e) {
|
|
@@ -766,8 +506,4 @@ class OneDrive extends EventEmitter {
|
|
|
766
506
|
}
|
|
767
507
|
}
|
|
768
508
|
|
|
769
|
-
|
|
770
|
-
MAX_SUBSCRIPTION_EXPIRATION_TIME,
|
|
771
|
-
driveItemToURL,
|
|
772
|
-
driveItemFromURL,
|
|
773
|
-
});
|
|
509
|
+
OneDrive.MAX_SUBSCRIPTION_EXPIRATION_TIME = MAX_SUBSCRIPTION_EXPIRATION_TIME;
|